From 9ffad035e06d61798a36a8c59135eeeb30fff694 Mon Sep 17 00:00:00 2001 From: cccs-rs <62077998+cccs-rs@users.noreply.github.com> Date: Mon, 4 Nov 2024 12:16:28 +0000 Subject: [PATCH] Simplify fetching of YARA rules for MACO extractors --- .gitignore | 184 +++++++++++++++++- modules/__init__.py | 0 modules/parsers/MACO/AgentTesla.py | 17 +- modules/parsers/MACO/AsyncRAT.py | 24 ++- modules/parsers/MACO/AuroraStealer.py | 7 +- modules/parsers/MACO/Azorult.py | 11 +- modules/parsers/MACO/BackOffLoader.py | 8 +- modules/parsers/MACO/BackOffPOS.py | 8 +- modules/parsers/MACO/BitPaymer.py | 9 +- modules/parsers/MACO/BlackDropper.py | 11 +- modules/parsers/MACO/BlackNix.py | 14 +- modules/parsers/MACO/Blister.py | 10 +- modules/parsers/MACO/BruteRatel.py | 14 +- modules/parsers/MACO/BuerLoader.py | 6 +- modules/parsers/MACO/BumbleBee.py | 10 +- modules/parsers/MACO/Carbanak.py | 9 +- modules/parsers/MACO/ChChes.py | 5 +- modules/parsers/MACO/CobaltStrikeBeacon.py | 26 ++- modules/parsers/MACO/CobaltStrikeStager.py | 6 +- modules/parsers/MACO/DCRat.py | 6 +- modules/parsers/MACO/DarkGate.py | 6 +- modules/parsers/MACO/DoppelPaymer.py | 11 +- modules/parsers/MACO/DridexLoader.py | 9 +- modules/parsers/MACO/Emotet.py | 19 +- modules/parsers/MACO/Enfal.py | 5 +- modules/parsers/MACO/EvilGrab.py | 10 +- modules/parsers/MACO/Fareit.py | 6 +- modules/parsers/MACO/Formbook.py | 6 +- modules/parsers/MACO/Greame.py | 4 +- modules/parsers/MACO/GuLoader.py | 5 +- .../parsers/MACO/Hancitor.py_deprecated.py | 6 +- modules/parsers/MACO/HttpBrowser.py | 9 +- modules/parsers/MACO/IcedID.py | 6 +- modules/parsers/MACO/IcedIDLoader.py | 6 +- modules/parsers/MACO/KoiLoader.py | 5 +- modules/parsers/MACO/Latrodectus.py | 10 +- modules/parsers/MACO/LokiBot.py | 6 +- modules/parsers/MACO/Lumma.py | 6 +- modules/parsers/MACO/NanoCore.py | 10 +- modules/parsers/MACO/Nighthawk.py | 6 +- modules/parsers/MACO/Njrat.py | 4 +- modules/parsers/MACO/Oyster.py | 6 +- modules/parsers/MACO/Pandora.py | 23 ++- modules/parsers/MACO/PhemedroneStealer.py | 4 +- modules/parsers/MACO/PikaBot.py | 24 ++- modules/parsers/MACO/PlugX.py | 4 +- modules/parsers/MACO/PoisonIvy.py | 4 +- modules/parsers/MACO/Punisher.py | 12 +- modules/parsers/MACO/QakBot.py | 5 +- modules/parsers/MACO/QuasarRAT.py | 6 +- modules/parsers/MACO/Quickbind.py | 10 +- modules/parsers/MACO/RCSession.py | 9 +- modules/parsers/MACO/REvil.py | 4 +- modules/parsers/MACO/RedLeaf.py | 5 +- modules/parsers/MACO/RedLine.py | 4 +- modules/parsers/MACO/Remcos.py | 6 +- modules/parsers/MACO/Retefe.py | 5 +- modules/parsers/MACO/Rhadamanthys.py | 6 +- modules/parsers/MACO/Rozena.py | 10 +- modules/parsers/MACO/SmallNet.py | 4 +- modules/parsers/MACO/SmokeLoader.py | 9 +- modules/parsers/MACO/Socks5Systemz.py | 15 +- modules/parsers/MACO/SparkRAT.py | 13 +- modules/parsers/MACO/SquirrelWaffle.py | 9 +- modules/parsers/MACO/Stealc.py | 9 +- modules/parsers/MACO/Strrat.py | 4 +- modules/parsers/MACO/TSCookie.py | 6 +- modules/parsers/MACO/TrickBot.py | 5 +- modules/parsers/MACO/UrsnifV3.py | 6 +- modules/parsers/MACO/VenomRat.py | 4 +- modules/parsers/MACO/WarzoneRAT.py | 4 +- modules/parsers/MACO/XWorm.py | 6 +- modules/parsers/MACO/XenoRAT.py | 6 +- modules/parsers/MACO/Zloader.py | 9 +- modules/parsers/__init__.py | 0 modules/parsers/utils.py | 40 ++++ pyproject.toml | 8 + 77 files changed, 654 insertions(+), 190 deletions(-) create mode 100644 modules/__init__.py create mode 100644 modules/parsers/__init__.py create mode 100644 modules/parsers/utils.py diff --git a/.gitignore b/.gitignore index e075e3fe..b00fa73a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,182 @@ -test.py -.DS_Store +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# Ignore YARA rules that were downloaded from the core for MACO extractors +*/parsers/yara/*.yar diff --git a/modules/__init__.py b/modules/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/modules/parsers/MACO/AgentTesla.py b/modules/parsers/MACO/AgentTesla.py index bd1b934e..f77d5b2d 100644 --- a/modules/parsers/MACO/AgentTesla.py +++ b/modules/parsers/MACO/AgentTesla.py @@ -1,8 +1,7 @@ -import os - -from cape_parsers.CAPE.community.AgentTesla import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.AgentTesla import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict) -> MACOModel: @@ -15,7 +14,11 @@ def convert_to_MACO(raw_config: dict) -> MACOModel: parsed_result = MACOModel(family="AgentTesla", other=raw_config) if protocol == "Telegram": - parsed_result.http.append(MACOModel.Http(uri=raw_config["C2"], password=raw_config["Password"], usage="c2")) + parsed_result.http.append( + MACOModel.Http( + uri=raw_config["C2"], password=raw_config["Password"], usage="c2" + ) + ) elif protocol in ["HTTP(S)", "Discord"]: parsed_result.http.append(MACOModel.Http(uri=raw_config["C2"], usage="c2")) @@ -43,7 +46,9 @@ def convert_to_MACO(raw_config: dict) -> MACOModel: parsed_result.smtp.append(MACOModel.SMTP(**smtp)) if "Persistence_Filename" in raw_config: - parsed_result.paths.append(MACOModel.Path(path=raw_config["Persistence_Filename"], usage="storage")) + parsed_result.paths.append( + MACOModel.Path(path=raw_config["Persistence_Filename"], usage="storage") + ) if "ExternalIPCheckServices" in raw_config: for service in raw_config["ExternalIPCheckServices"]: @@ -57,7 +62,7 @@ class AgentTesla(Extractor): family = "AgentTesla" last_modified = "2024-10-20" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/AsyncRAT.py b/modules/parsers/MACO/AsyncRAT.py index 558ebc4d..6459c8e2 100644 --- a/modules/parsers/MACO/AsyncRAT.py +++ b/modules/parsers/MACO/AsyncRAT.py @@ -1,8 +1,9 @@ import os -from cape_parsers.CAPE.community.AsyncRAT import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.AsyncRAT import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict) -> MACOModel: @@ -25,16 +26,29 @@ def convert_to_MACO(raw_config: dict) -> MACOModel: # Installation Path if raw_config.get("Folder"): - parsed_result.paths.append(MACOModel.Path(path=os.path.join(raw_config["Folder"], raw_config["Filename"]), usage="install")) + parsed_result.paths.append( + MACOModel.Path( + path=os.path.join(raw_config["Folder"], raw_config["Filename"]), + usage="install", + ) + ) # C2s for i in range(len(raw_config.get("C2s", []))): - parsed_result.http.append(MACOModel.Http(hostname=raw_config["C2s"][i], port=int(raw_config["Ports"][i]), usage="c2")) + parsed_result.http.append( + MACOModel.Http( + hostname=raw_config["C2s"][i], + port=int(raw_config["Ports"][i]), + usage="c2", + ) + ) # Pastebin if raw_config.get("Pastebin") not in ["null", None]: # TODO: Is it used to download the C2 information if not embedded? # Ref: https://www.netskope.com/blog/asyncrat-using-fully-undetected-downloader - parsed_result.http.append(MACOModel.Http(uri=raw_config["Pastebin"], usage="download")) + parsed_result.http.append( + MACOModel.Http(uri=raw_config["Pastebin"], usage="download") + ) return parsed_result @@ -44,7 +58,7 @@ class AsyncRAT(Extractor): family = "AsyncRAT" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/AuroraStealer.py b/modules/parsers/MACO/AuroraStealer.py index f9b50214..06677c0b 100644 --- a/modules/parsers/MACO/AuroraStealer.py +++ b/modules/parsers/MACO/AuroraStealer.py @@ -1,8 +1,7 @@ -import os - -from cape_parsers.CAPE.community.AuroraStealer import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.AuroraStealer import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -22,7 +21,7 @@ class AuroraStealer(Extractor): family = "AuroraStealer" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/Azorult.py b/modules/parsers/MACO/Azorult.py index be1137ec..62868d9c 100644 --- a/modules/parsers/MACO/Azorult.py +++ b/modules/parsers/MACO/Azorult.py @@ -1,13 +1,18 @@ -from cape_parsers.CAPE.core.Azorult import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.Azorult import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): if not raw_config: return None - return MACOModel(family="Azorult", http=[MACOModel.Http(hostname=raw_config["address"])], other=raw_config) + return MACOModel( + family="Azorult", + http=[MACOModel.Http(hostname=raw_config["address"])], + other=raw_config, + ) class Azorult(Extractor): @@ -15,7 +20,7 @@ class Azorult(Extractor): family = "Azorult" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = rule_source + yara_rule = get_YARA_rule(family) or rule_source def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/BackOffLoader.py b/modules/parsers/MACO/BackOffLoader.py index a8e37167..cdc3954a 100644 --- a/modules/parsers/MACO/BackOffLoader.py +++ b/modules/parsers/MACO/BackOffLoader.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.community.BackOffLoader import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.BackOffLoader import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -14,7 +15,9 @@ def convert_to_MACO(raw_config: dict): # Encryption details parsed_result.encryption.append( - MACOModel.Encryption(algorithm="rc4", key=raw_config["EncryptionKey"], seed=raw_config["RC4Seed"]) + MACOModel.Encryption( + algorithm="rc4", key=raw_config["EncryptionKey"], seed=raw_config["RC4Seed"] + ) ) for url in raw_config["URLs"]: parsed_result.http.append(MACOModel.Http(url=url)) @@ -27,6 +30,7 @@ class BackOffLoader(Extractor): family = "BackOffLoader" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/BackOffPOS.py b/modules/parsers/MACO/BackOffPOS.py index ad0018c6..620985ff 100644 --- a/modules/parsers/MACO/BackOffPOS.py +++ b/modules/parsers/MACO/BackOffPOS.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.community.BackOffPOS import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.BackOffPOS import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -14,7 +15,9 @@ def convert_to_MACO(raw_config: dict): # Encryption details parsed_result.encryption.append( - MACOModel.Encryption(algorithm="rc4", key=raw_config["EncryptionKey"], seed=raw_config["RC4Seed"]) + MACOModel.Encryption( + algorithm="rc4", key=raw_config["EncryptionKey"], seed=raw_config["RC4Seed"] + ) ) for url in raw_config["URLs"]: parsed_result.http.append(MACOModel.Http(url=url)) @@ -27,6 +30,7 @@ class BackOffPOS(Extractor): family = "BackOffPOS" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/BitPaymer.py b/modules/parsers/MACO/BitPaymer.py index c0742057..4849612c 100644 --- a/modules/parsers/MACO/BitPaymer.py +++ b/modules/parsers/MACO/BitPaymer.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.BitPaymer import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.BitPaymer import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -13,7 +14,9 @@ def convert_to_MACO(raw_config: dict): parsed_result.decoded_strings = raw_config["strings"] # Encryption details - parsed_result.encryption.append(MACOModel.Encryption(algorithm="rsa", public_key=raw_config["RSA public key"])) + parsed_result.encryption.append( + MACOModel.Encryption(algorithm="rsa", public_key=raw_config["RSA public key"]) + ) return parsed_result @@ -22,6 +25,8 @@ class BitPaymer(Extractor): family = "BitPaymer" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/MACO/BlackDropper.py b/modules/parsers/MACO/BlackDropper.py index 28bd8b4a..f0e8a7bd 100644 --- a/modules/parsers/MACO/BlackDropper.py +++ b/modules/parsers/MACO/BlackDropper.py @@ -1,15 +1,16 @@ -import os - -from cape_parsers.CAPE.core.BlackDropper import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.BlackDropper import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): if not raw_config: return None - parsed_result = MACOModel(family="BlackDropper", campaign_id=[raw_config["campaign"]], other=raw_config) + parsed_result = MACOModel( + family="BlackDropper", campaign_id=[raw_config["campaign"]], other=raw_config + ) for dir in raw_config.get("directories", []): parsed_result.paths.append(MACOModel.Path(path=dir)) @@ -25,7 +26,7 @@ class BlackDropper(Extractor): family = "BlackDropper" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/BlackNix.py b/modules/parsers/MACO/BlackNix.py index eeac5d35..f3fd6332 100644 --- a/modules/parsers/MACO/BlackNix.py +++ b/modules/parsers/MACO/BlackNix.py @@ -1,8 +1,9 @@ import os -from cape_parsers.CAPE.community.BlackNix import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.BlackNix import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -47,11 +48,17 @@ def convert_to_MACO(raw_config: dict): # Install Path parsed_result.paths.append( - MACOModel.Path(path=os.path.join(raw_config["Install Path"], raw_config["Install Name"]), usage="install") + MACOModel.Path( + path=os.path.join(raw_config["Install Path"], raw_config["Install Name"]), + usage="install", + ) ) # Campaign Group/Name - parsed_result.campaign_id = [raw_config["Campaign Name"], raw_config["Campaign Group"]] + parsed_result.campaign_id = [ + raw_config["Campaign Name"], + raw_config["Campaign Group"], + ] return parsed_result @@ -60,6 +67,7 @@ class BlackNix(Extractor): family = "BlackNix" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/Blister.py b/modules/parsers/MACO/Blister.py index f1b7e10b..0aea544a 100644 --- a/modules/parsers/MACO/Blister.py +++ b/modules/parsers/MACO/Blister.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.core.Blister import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.Blister import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -19,7 +19,9 @@ def convert_to_MACO(raw_config: dict): # Rabbit encryption parsed_result.encryption.append( - MACOModel.Encryption(algorithm="rabbit", key=raw_config["Rabbit key"], iv=raw_config["Rabbit IV"]) + MACOModel.Encryption( + algorithm="rabbit", key=raw_config["Rabbit key"], iv=raw_config["Rabbit IV"] + ) ) return parsed_result @@ -29,7 +31,7 @@ class Blister(Extractor): family = "Blister" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/BruteRatel.py b/modules/parsers/MACO/BruteRatel.py index 5bae7e53..617dd8d8 100644 --- a/modules/parsers/MACO/BruteRatel.py +++ b/modules/parsers/MACO/BruteRatel.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.core.BruteRatel import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.BruteRatel import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -14,7 +14,13 @@ def convert_to_MACO(raw_config: dict): for url in raw_config["C2"]: for path in raw_config["URI"]: parsed_result.http.append( - MACOModel.Http(uri=url, user_agent=raw_config["User Agent"], port=raw_config["Port"], path=path, usage="c2") + MACOModel.Http( + uri=url, + user_agent=raw_config["User Agent"], + port=raw_config["Port"], + path=path, + usage="c2", + ) ) return parsed_result @@ -25,7 +31,7 @@ class BruteRatel(Extractor): family = "BruteRatel" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/BuerLoader.py b/modules/parsers/MACO/BuerLoader.py index 687333c2..2dc5925a 100644 --- a/modules/parsers/MACO/BuerLoader.py +++ b/modules/parsers/MACO/BuerLoader.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.core.BuerLoader import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.BuerLoader import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -21,7 +21,7 @@ class BuerLoader(Extractor): family = "BuerLoader" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/BumbleBee.py b/modules/parsers/MACO/BumbleBee.py index 4709551d..187ede14 100644 --- a/modules/parsers/MACO/BumbleBee.py +++ b/modules/parsers/MACO/BumbleBee.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.core.BumbleBee import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.BumbleBee import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -29,7 +29,9 @@ def convert_to_MACO(raw_config: dict): # RC4 Key if raw_config.get("RC4 Key"): - parsed_result.encryption.append(MACOModel.Encryption(algorithm="rc4", key=raw_config["RC4 Key"])) + parsed_result.encryption.append( + MACOModel.Encryption(algorithm="rc4", key=raw_config["RC4 Key"]) + ) return parsed_result @@ -39,7 +41,7 @@ class BumbleBee(Extractor): family = "BumbleBee" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/Carbanak.py b/modules/parsers/MACO/Carbanak.py index a83a6eb8..34ac9705 100644 --- a/modules/parsers/MACO/Carbanak.py +++ b/modules/parsers/MACO/Carbanak.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.community.Carbanak import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.Carbanak import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -21,7 +22,9 @@ def convert_to_MACO(raw_config: dict): # C2 if raw_config.get("C2"): if isinstance(raw_config["C2"], str): - parsed_result.http.append(MACOModel.Http(hostname=raw_config["C2"], usage="c2")) + parsed_result.http.append( + MACOModel.Http(hostname=raw_config["C2"], usage="c2") + ) else: for c2 in raw_config["C2"]: parsed_result.http.append(MACOModel.Http(hostname=c2, usage="c2")) @@ -38,6 +41,8 @@ class Carbanak(Extractor): family = "Carbanak" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/MACO/ChChes.py b/modules/parsers/MACO/ChChes.py index bb3db418..987cb964 100644 --- a/modules/parsers/MACO/ChChes.py +++ b/modules/parsers/MACO/ChChes.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.ChChes import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.ChChes import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -21,6 +22,8 @@ class ChChes(Extractor): family = "ChChes" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/MACO/CobaltStrikeBeacon.py b/modules/parsers/MACO/CobaltStrikeBeacon.py index 8d5707e9..35dd02c8 100644 --- a/modules/parsers/MACO/CobaltStrikeBeacon.py +++ b/modules/parsers/MACO/CobaltStrikeBeacon.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.community.CobaltStrikeBeacon import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.CobaltStrikeBeacon import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -12,7 +12,11 @@ def convert_to_MACO(raw_config: dict): parsed_result = MACOModel(family="CobaltStrikeBeacon", other=raw_config) clean_config = {k: v for k, v in raw_config.items() if v != "Not Found"} - capabilities = {k[1:]: clean_config.pop(k) for k in list(clean_config.keys()) if clean_config[k] in ["True", "False"]} + capabilities = { + k[1:]: clean_config.pop(k) + for k in list(clean_config.keys()) + if clean_config[k] in ["True", "False"] + } for capability, enabled in capabilities.items(): if enabled.lower() == "true": @@ -23,9 +27,19 @@ def convert_to_MACO(raw_config: dict): if "C2Server" in clean_config: host, get_path = clean_config.pop("C2Server").split(",") port = clean_config.pop("Port") - parsed_result.http.append(MACOModel.Http(hostname=host, port=port, method="GET", path=get_path, usage="c2")) parsed_result.http.append( - MACOModel.Http(hostname=host, port=port, method="POST", path=clean_config.pop("HttpPostUri"), usage="c2") + MACOModel.Http( + hostname=host, port=port, method="GET", path=get_path, usage="c2" + ) + ) + parsed_result.http.append( + MACOModel.Http( + hostname=host, + port=port, + method="POST", + path=clean_config.pop("HttpPostUri"), + usage="c2", + ) ) parsed_result.sleep_delay = clean_config.pop("SleepTime") @@ -43,7 +57,7 @@ class CobaltStrikeBeacon(Extractor): family = "CobaltStrikeBeacon" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/CobaltStrikeStager.py b/modules/parsers/MACO/CobaltStrikeStager.py index 81330aeb..51eeb432 100644 --- a/modules/parsers/MACO/CobaltStrikeStager.py +++ b/modules/parsers/MACO/CobaltStrikeStager.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.community.CobaltStrikeStager import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.CobaltStrikeStager import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -19,7 +19,7 @@ class CobaltStrikeStager(Extractor): family = "CobaltStrikeStager" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/DCRat.py b/modules/parsers/MACO/DCRat.py index 84e558ad..f9f3f165 100644 --- a/modules/parsers/MACO/DCRat.py +++ b/modules/parsers/MACO/DCRat.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.community.DCRat import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.DCRat import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -20,7 +20,7 @@ class DCRat(Extractor): family = "DCRat" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/DarkGate.py b/modules/parsers/MACO/DarkGate.py index 86adeeda..b4e7efb7 100644 --- a/modules/parsers/MACO/DarkGate.py +++ b/modules/parsers/MACO/DarkGate.py @@ -1,9 +1,9 @@ -import os from copy import deepcopy -from cape_parsers.CAPE.core.DarkGate import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.DarkGate import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -45,7 +45,7 @@ class DarkGate(Extractor): family = "DarkGate" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/DoppelPaymer.py b/modules/parsers/MACO/DoppelPaymer.py index 3f1d5456..d3350b34 100644 --- a/modules/parsers/MACO/DoppelPaymer.py +++ b/modules/parsers/MACO/DoppelPaymer.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.DoppelPaymer import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.DoppelPaymer import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -13,7 +14,11 @@ def convert_to_MACO(raw_config: dict): parsed_result.decoded_strings = raw_config["strings"] if "RSA public key" in raw_config: - parsed_result.encryption.append(MACOModel.Encryption(algorithm="RSA", public_key=raw_config["RSA public key"])) + parsed_result.encryption.append( + MACOModel.Encryption( + algorithm="RSA", public_key=raw_config["RSA public key"] + ) + ) return parsed_result @@ -23,6 +28,8 @@ class DoppelPaymer(Extractor): family = "DoppelPaymer" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/MACO/DridexLoader.py b/modules/parsers/MACO/DridexLoader.py index c5a3f2ce..6c436c60 100644 --- a/modules/parsers/MACO/DridexLoader.py +++ b/modules/parsers/MACO/DridexLoader.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.DridexLoader import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.DridexLoader import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -13,7 +14,9 @@ def convert_to_MACO(raw_config: dict): parsed_result.http.append(MACOModel.Http(uri=c2_address, usage="c2")) if "RC4 key" in raw_config: - parsed_result.encryption.append(MACOModel.Encryption(algorithm="RC4", key=raw_config["RC4 key"])) + parsed_result.encryption.append( + MACOModel.Encryption(algorithm="RC4", key=raw_config["RC4 key"]) + ) if "Botnet ID" in raw_config: parsed_result.identifier.append(raw_config["Botnet ID"]) @@ -26,6 +29,8 @@ class DridexLoader(Extractor): family = "DridexLoader" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/MACO/Emotet.py b/modules/parsers/MACO/Emotet.py index 6e73c42e..0b96f889 100644 --- a/modules/parsers/MACO/Emotet.py +++ b/modules/parsers/MACO/Emotet.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.Emotet import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.Emotet import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -13,9 +14,17 @@ def convert_to_MACO(raw_config: dict): parsed_result.http.append(MACOModel.Http(uri=c2_address, usage="c2")) if "RC4 public key" in raw_config: - parsed_result.encryption.append(MACOModel.Encryption(algorithm="RC4", public_key=raw_config["RSA public key"])) - - parsed_result.other = {k: raw_config[k] for k in raw_config.keys() if k not in ["address", "RSA public key"]} + parsed_result.encryption.append( + MACOModel.Encryption( + algorithm="RC4", public_key=raw_config["RSA public key"] + ) + ) + + parsed_result.other = { + k: raw_config[k] + for k in raw_config.keys() + if k not in ["address", "RSA public key"] + } return parsed_result @@ -25,6 +34,8 @@ class Emotet(Extractor): family = "Emotet" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/MACO/Enfal.py b/modules/parsers/MACO/Enfal.py index c4137806..3b3a3656 100644 --- a/modules/parsers/MACO/Enfal.py +++ b/modules/parsers/MACO/Enfal.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.Enfal import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.Enfal import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -18,6 +19,8 @@ class Enfal(Extractor): family = "Enfal" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/MACO/EvilGrab.py b/modules/parsers/MACO/EvilGrab.py index c3b7e2d2..3d5e047d 100644 --- a/modules/parsers/MACO/EvilGrab.py +++ b/modules/parsers/MACO/EvilGrab.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.EvilGrab import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.EvilGrab import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -20,7 +21,10 @@ def convert_to_MACO(raw_config: dict): if "c2_address" in raw_config: parsed_result.http.append( - parsed_result.Http(uri=raw_config["c2_address"], port=raw_config["port"][0] if "port" in raw_config else None) + parsed_result.Http( + uri=raw_config["c2_address"], + port=raw_config["port"][0] if "port" in raw_config else None, + ) ) return parsed_result @@ -31,6 +35,8 @@ class EvilGrab(Extractor): family = "EvilGrab" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/MACO/Fareit.py b/modules/parsers/MACO/Fareit.py index dccb9f3a..3715d76b 100644 --- a/modules/parsers/MACO/Fareit.py +++ b/modules/parsers/MACO/Fareit.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.community.Fareit import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.Fareit import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -20,7 +20,7 @@ class Fareit(Extractor): family = "Fareit" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/Formbook.py b/modules/parsers/MACO/Formbook.py index db8aef01..e1b2de86 100644 --- a/modules/parsers/MACO/Formbook.py +++ b/modules/parsers/MACO/Formbook.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.core.Formbook import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.Formbook import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -25,7 +25,7 @@ class Formbook(Extractor): family = "Formbook" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/Greame.py b/modules/parsers/MACO/Greame.py index 8a132af3..b4e8a350 100644 --- a/modules/parsers/MACO/Greame.py +++ b/modules/parsers/MACO/Greame.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.community.Greame import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.Greame import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -17,6 +18,7 @@ class Greame(Extractor): family = "Greame" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/GuLoader.py b/modules/parsers/MACO/GuLoader.py index 24ec8e4a..061ec7ca 100644 --- a/modules/parsers/MACO/GuLoader.py +++ b/modules/parsers/MACO/GuLoader.py @@ -1,8 +1,9 @@ import os -from cape_parsers.CAPE.core.GuLoader import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.GuLoader import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -22,7 +23,7 @@ class GuLoader(Extractor): family = "GuLoader" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], "data/yara/CAPE/Guloader.yar")).read() + yara_rule = get_YARA_rule("Guloader") def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/Hancitor.py_deprecated.py b/modules/parsers/MACO/Hancitor.py_deprecated.py index e04a4c52..83323526 100644 --- a/modules/parsers/MACO/Hancitor.py_deprecated.py +++ b/modules/parsers/MACO/Hancitor.py_deprecated.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.Hancitor import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.Hancitor import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -25,7 +25,7 @@ class Hancitor(Extractor): family = "Hancitor" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/HttpBrowser.py b/modules/parsers/MACO/HttpBrowser.py index 44f29691..a9e08f04 100644 --- a/modules/parsers/MACO/HttpBrowser.py +++ b/modules/parsers/MACO/HttpBrowser.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.HttpBrowser import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.HttpBrowser import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -12,7 +13,9 @@ def convert_to_MACO(raw_config: dict): port = raw_config["port"][0] if "port" in raw_config else None if "c2_address" in raw_config: - parsed_result.http.append(MACOModel.Http(uri=raw_config["c2_address"], port=port, usage="c2")) + parsed_result.http.append( + MACOModel.Http(uri=raw_config["c2_address"], port=port, usage="c2") + ) if "filepath" in raw_config: parsed_result.paths.append(MACOModel.Path(path=raw_config["filepath"])) @@ -28,6 +31,8 @@ class HttpBrowser(Extractor): family = "HttpBrowser" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/MACO/IcedID.py b/modules/parsers/MACO/IcedID.py index 806e2d39..40a85937 100644 --- a/modules/parsers/MACO/IcedID.py +++ b/modules/parsers/MACO/IcedID.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.core.IcedID import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.IcedID import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -17,7 +17,7 @@ class IcedID(Extractor): family = "IcedID" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/IcedIDLoader.py b/modules/parsers/MACO/IcedIDLoader.py index 7fc80c15..496225d5 100644 --- a/modules/parsers/MACO/IcedIDLoader.py +++ b/modules/parsers/MACO/IcedIDLoader.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.core.IcedIDLoader import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.IcedIDLoader import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -25,7 +25,7 @@ class IcedIDLoader(Extractor): family = "IcedIDLoader" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/KoiLoader.py b/modules/parsers/MACO/KoiLoader.py index 25d83390..9e8df88d 100644 --- a/modules/parsers/MACO/KoiLoader.py +++ b/modules/parsers/MACO/KoiLoader.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.community.KoiLoader import RULE_SOURCE, extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.KoiLoader import RULE_SOURCE, extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -20,6 +21,8 @@ class KoiLoader(Extractor): family = "KoiLoader" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = RULE_SOURCE def run(self, stream, matches): diff --git a/modules/parsers/MACO/Latrodectus.py b/modules/parsers/MACO/Latrodectus.py index 81d4fe60..a338d2af 100644 --- a/modules/parsers/MACO/Latrodectus.py +++ b/modules/parsers/MACO/Latrodectus.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.core.Latrodectus import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.Latrodectus import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -24,7 +24,9 @@ def convert_to_MACO(raw_config: dict): parsed_result.version = raw_config["Version"] if "RC4 key" in raw_config: - parsed_result.encryption.append(MACOModel.Encryption(algorithm="RC4", key=raw_config["RC4 key"])) + parsed_result.encryption.append( + MACOModel.Encryption(algorithm="RC4", key=raw_config["RC4 key"]) + ) if "Strings" in raw_config: parsed_result.decoded_strings = raw_config["Strings"] @@ -37,7 +39,7 @@ class Latrodectus(Extractor): family = "Latrodectus" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/LokiBot.py b/modules/parsers/MACO/LokiBot.py index 61480965..4c0c94b7 100644 --- a/modules/parsers/MACO/LokiBot.py +++ b/modules/parsers/MACO/LokiBot.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.community.LokiBot import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.LokiBot import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -22,7 +22,7 @@ class LokiBot(Extractor): family = "LokiBot" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/Lumma.py b/modules/parsers/MACO/Lumma.py index 61053bda..152035a9 100644 --- a/modules/parsers/MACO/Lumma.py +++ b/modules/parsers/MACO/Lumma.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.community.Lumma import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.Lumma import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -22,7 +22,7 @@ class Lumma(Extractor): family = "Lumma" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/NanoCore.py b/modules/parsers/MACO/NanoCore.py index 1aaab0b3..d5b24e65 100644 --- a/modules/parsers/MACO/NanoCore.py +++ b/modules/parsers/MACO/NanoCore.py @@ -1,8 +1,9 @@ from copy import deepcopy -from cape_parsers.CAPE.community.NanoCore import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.NanoCore import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -12,7 +13,11 @@ def convert_to_MACO(raw_config: dict): parsed_result = MACOModel(family="NanoCore", other=raw_config) config_copy = deepcopy(raw_config) - capabilities = {k: config_copy.pop(k) for k in list(config_copy.keys()) if config_copy[k] in ["True", "False"]} + capabilities = { + k: config_copy.pop(k) + for k in list(config_copy.keys()) + if config_copy[k] in ["True", "False"] + } if "Version" in config_copy: parsed_result.version = config_copy.pop("Version") @@ -38,6 +43,7 @@ class NanoCore(Extractor): family = "NanoCore" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/Nighthawk.py b/modules/parsers/MACO/Nighthawk.py index fa2d8d27..616aa6fd 100644 --- a/modules/parsers/MACO/Nighthawk.py +++ b/modules/parsers/MACO/Nighthawk.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.community.Nighthawk import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.Nighthawk import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -19,7 +19,7 @@ class Nighthawk(Extractor): family = "Nighthawk" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/Njrat.py b/modules/parsers/MACO/Njrat.py index 19c544f2..4a8ab60d 100644 --- a/modules/parsers/MACO/Njrat.py +++ b/modules/parsers/MACO/Njrat.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.community.Njrat import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.Njrat import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -27,6 +28,7 @@ class Njrat(Extractor): family = "Njrat" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/Oyster.py b/modules/parsers/MACO/Oyster.py index 3527f77a..8c012da9 100644 --- a/modules/parsers/MACO/Oyster.py +++ b/modules/parsers/MACO/Oyster.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.core.Oyster import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.Oyster import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -28,7 +28,7 @@ class Oyster(Extractor): family = "Oyster" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/Pandora.py b/modules/parsers/MACO/Pandora.py index 13bbf2c5..84c815f3 100644 --- a/modules/parsers/MACO/Pandora.py +++ b/modules/parsers/MACO/Pandora.py @@ -1,9 +1,10 @@ import os from copy import deepcopy -from cape_parsers.CAPE.community.Pandora import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.Pandora import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -16,16 +17,29 @@ def convert_to_MACO(raw_config: dict): mutex=[config_copy.pop("Mutex")], campaign_id=[config_copy.pop("Campaign ID")], version=config_copy.pop("Version"), - http=[dict(hostname=config_copy.pop("Domain"), port=config_copy.pop("Port"), password=config_copy.pop("Password"))], + http=[ + dict( + hostname=config_copy.pop("Domain"), + port=config_copy.pop("Port"), + password=config_copy.pop("Password"), + ) + ], other=raw_config, ) parsed_result.paths.append( - MACOModel.Path(path=os.path.join(config_copy.pop("Install Path"), config_copy.pop("Install Name")), usage="install") + MACOModel.Path( + path=os.path.join( + config_copy.pop("Install Path"), config_copy.pop("Install Name") + ), + usage="install", + ) ) parsed_result.registry.append(MACOModel.Registry(key=config_copy.pop("HKCU Key"))) - parsed_result.registry.append(MACOModel.Registry(key=config_copy.pop("ActiveX Key"))) + parsed_result.registry.append( + MACOModel.Registry(key=config_copy.pop("ActiveX Key")) + ) for field in list(config_copy.keys()): # TODO: Unsure what's the value of the remaining fields @@ -44,6 +58,7 @@ class Pandora(Extractor): family = "Pandora" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/PhemedroneStealer.py b/modules/parsers/MACO/PhemedroneStealer.py index 67a233ad..f865b0f9 100644 --- a/modules/parsers/MACO/PhemedroneStealer.py +++ b/modules/parsers/MACO/PhemedroneStealer.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.community.PhemedroneStealer import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.PhemedroneStealer import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -17,6 +18,7 @@ class PhemedroneStealer(Extractor): family = "PhemedroneStealer" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/PikaBot.py b/modules/parsers/MACO/PikaBot.py index 062d7088..4b54c0fe 100644 --- a/modules/parsers/MACO/PikaBot.py +++ b/modules/parsers/MACO/PikaBot.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.PikaBot import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.PikaBot import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -10,15 +11,26 @@ def convert_to_MACO(raw_config: dict): parsed_result = MACOModel(family="PikaBot", other=raw_config) if "C2" in raw_config: - [parsed_result.http.append(MACOModel.Http(uri=c2, usage="c2")) for c2 in raw_config["C2"]] - parsed_result.binaries.append(MACOModel.Binary(datatype="payload", data=raw_config["Powershell"])) + [ + parsed_result.http.append(MACOModel.Http(uri=c2, usage="c2")) + for c2 in raw_config["C2"] + ] + parsed_result.binaries.append( + MACOModel.Binary(datatype="payload", data=raw_config["Powershell"]) + ) elif "C2s" in raw_config: parsed_result.version = raw_config["Version"] parsed_result.campaign_id.append(raw_config["Campaign Name"]) - parsed_result.registry.append(MACOModel.Registry(key=raw_config["Registry Key"])) + parsed_result.registry.append( + MACOModel.Registry(key=raw_config["Registry Key"]) + ) for c2 in raw_config["C2s"]: host, port = c2.split(":") - parsed_result.http.append(MACOModel.Http(hostname=host, port=port, user_agent=raw_config["User Agent"])) + parsed_result.http.append( + MACOModel.Http( + hostname=host, port=port, user_agent=raw_config["User Agent"] + ) + ) return parsed_result @@ -28,6 +40,8 @@ class PikaBot(Extractor): family = "PikaBot" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/MACO/PlugX.py b/modules/parsers/MACO/PlugX.py index 12fa1375..f6ba61d4 100644 --- a/modules/parsers/MACO/PlugX.py +++ b/modules/parsers/MACO/PlugX.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.PlugX import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.PlugX import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -17,6 +18,7 @@ class PlugX(Extractor): family = "PlugX" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/PoisonIvy.py b/modules/parsers/MACO/PoisonIvy.py index 0f3363fd..602e5d64 100644 --- a/modules/parsers/MACO/PoisonIvy.py +++ b/modules/parsers/MACO/PoisonIvy.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.community.PoisonIvy import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.PoisonIvy import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -37,6 +38,7 @@ class PoisonIvy(Extractor): family = "PoisonIvy" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) def run(self, stream, matches): output = extract_config(stream.read()) diff --git a/modules/parsers/MACO/Punisher.py b/modules/parsers/MACO/Punisher.py index c645f6f5..d6f11c21 100644 --- a/modules/parsers/MACO/Punisher.py +++ b/modules/parsers/MACO/Punisher.py @@ -1,9 +1,10 @@ import os from copy import deepcopy -from cape_parsers.CAPE.community.Punisher import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.Punisher import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -16,7 +17,13 @@ def convert_to_MACO(raw_config: dict): campaign_id=config_copy["Campaign Name"], password=[config_copy["Password"]], registry=[MACOModel.Registry(key=config_copy["Registry Key"])], - paths=[MACOModel.Path(path=os.path.join(config_copy["Install Path"], config_copy["Install Name"]))], + paths=[ + MACOModel.Path( + path=os.path.join( + config_copy["Install Path"], config_copy["Install Name"] + ) + ) + ], http=[MACOModel.Http(hostname=config_copy["Domain"], port=config_copy["Port"])], other=raw_config, ) @@ -38,6 +45,7 @@ class Punisher(Extractor): family = "Punisher" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) def run(self, stream, matches): output = extract_config(stream.read()) diff --git a/modules/parsers/MACO/QakBot.py b/modules/parsers/MACO/QakBot.py index 05fc8bdd..02fe6af4 100644 --- a/modules/parsers/MACO/QakBot.py +++ b/modules/parsers/MACO/QakBot.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.QakBot import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.QakBot import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -21,6 +22,8 @@ class QakBot(Extractor): family = "QakBot" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/MACO/QuasarRAT.py b/modules/parsers/MACO/QuasarRAT.py index 22664aa4..628d8a9d 100644 --- a/modules/parsers/MACO/QuasarRAT.py +++ b/modules/parsers/MACO/QuasarRAT.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.community.QuasarRAT import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.QuasarRAT import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -19,7 +19,7 @@ class QuasarRAT(Extractor): family = "QuasarRAT" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/Quickbind.py b/modules/parsers/MACO/Quickbind.py index bd933fe6..4ada459c 100644 --- a/modules/parsers/MACO/Quickbind.py +++ b/modules/parsers/MACO/Quickbind.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.core.Quickbind import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.Quickbind import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -18,7 +18,9 @@ def convert_to_MACO(raw_config: dict): parsed_result.http.append(MACOModel.Http(hostname=c2, usage="c2")) if "Encryption Key" in raw_config: - parsed_result.encryption.append(MACOModel.Encryption(key=raw_config["Encryption Key"])) + parsed_result.encryption.append( + MACOModel.Encryption(key=raw_config["Encryption Key"]) + ) return parsed_result @@ -28,7 +30,7 @@ class Quickbind(Extractor): family = "Quickbind" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/RCSession.py b/modules/parsers/MACO/RCSession.py index f43913ad..657abd2e 100644 --- a/modules/parsers/MACO/RCSession.py +++ b/modules/parsers/MACO/RCSession.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.RCSession import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.RCSession import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -13,7 +14,9 @@ def convert_to_MACO(raw_config: dict): parsed_result.http.append(MACOModel.Http(hostname=address, usage="c2")) if "directory" in raw_config: - parsed_result.paths.append(MACOModel.Path(path=raw_config["directory"], usage="install")) + parsed_result.paths.append( + MACOModel.Path(path=raw_config["directory"], usage="install") + ) service = {} @@ -37,6 +40,8 @@ class RCSession(Extractor): family = "RCSession" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/MACO/REvil.py b/modules/parsers/MACO/REvil.py index 0ee0b9b9..a2527f39 100644 --- a/modules/parsers/MACO/REvil.py +++ b/modules/parsers/MACO/REvil.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.community.REvil import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.REvil import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -17,6 +18,7 @@ class REvil(Extractor): family = "REvil" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/RedLeaf.py b/modules/parsers/MACO/RedLeaf.py index 1cb35dc6..c356f20c 100644 --- a/modules/parsers/MACO/RedLeaf.py +++ b/modules/parsers/MACO/RedLeaf.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.RedLeaf import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.RedLeaf import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -29,6 +30,8 @@ class RedLeaf(Extractor): family = "RedLeaf" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/MACO/RedLine.py b/modules/parsers/MACO/RedLine.py index 44475d9f..ef48073b 100644 --- a/modules/parsers/MACO/RedLine.py +++ b/modules/parsers/MACO/RedLine.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.RedLine import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.RedLine import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -21,6 +22,7 @@ class RedLine(Extractor): family = "RedLine" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/Remcos.py b/modules/parsers/MACO/Remcos.py index 8487cbb7..aa1829e9 100644 --- a/modules/parsers/MACO/Remcos.py +++ b/modules/parsers/MACO/Remcos.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.core.Remcos import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.Remcos import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -19,7 +19,7 @@ class Remcos(Extractor): family = "Remcos" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/Retefe.py b/modules/parsers/MACO/Retefe.py index c78b2048..76b5abb7 100644 --- a/modules/parsers/MACO/Retefe.py +++ b/modules/parsers/MACO/Retefe.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.community.Retefe import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.Retefe import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -17,6 +18,8 @@ class Retefe(Extractor): family = "Retefe" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/MACO/Rhadamanthys.py b/modules/parsers/MACO/Rhadamanthys.py index accbaf4b..991da443 100644 --- a/modules/parsers/MACO/Rhadamanthys.py +++ b/modules/parsers/MACO/Rhadamanthys.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.core.Rhadamanthys import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.Rhadamanthys import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -20,7 +20,7 @@ class Rhadamanthys(Extractor): family = "Rhadamanthys" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/Rozena.py b/modules/parsers/MACO/Rozena.py index d986c6f3..7f41a2c7 100644 --- a/modules/parsers/MACO/Rozena.py +++ b/modules/parsers/MACO/Rozena.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.community.Rozena import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.Rozena import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -10,7 +10,9 @@ def convert_to_MACO(raw_config: dict): return None parsed_result = MACOModel(family="Rozena", other=raw_config) - parsed_result.http = [MACOModel.Http(hostname=raw_config["C2"], port=raw_config["Port"], usage="c2")] + parsed_result.http = [ + MACOModel.Http(hostname=raw_config["C2"], port=raw_config["Port"], usage="c2") + ] return parsed_result @@ -20,7 +22,7 @@ class Rozena(Extractor): family = "Rozena" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/SmallNet.py b/modules/parsers/MACO/SmallNet.py index 02a2c8ba..c9e932e5 100644 --- a/modules/parsers/MACO/SmallNet.py +++ b/modules/parsers/MACO/SmallNet.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.community.SmallNet import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.SmallNet import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -17,6 +18,7 @@ class SmallNet(Extractor): family = "SmallNet" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) def run(self, stream, matches): output = extract_config(stream.read()) diff --git a/modules/parsers/MACO/SmokeLoader.py b/modules/parsers/MACO/SmokeLoader.py index 60a75169..8023697c 100644 --- a/modules/parsers/MACO/SmokeLoader.py +++ b/modules/parsers/MACO/SmokeLoader.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.SmokeLoader import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.SmokeLoader import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -8,7 +9,9 @@ def convert_to_MACO(raw_config: dict): return None parsed_result = MACOModel( - family="SmokeLoader", other=raw_config, http=[MACOModel.Http(uri=c2, usage="c2") for c2 in raw_config["C2s"]] + family="SmokeLoader", + other=raw_config, + http=[MACOModel.Http(uri=c2, usage="c2") for c2 in raw_config["C2s"]], ) return parsed_result @@ -19,6 +22,8 @@ class SmokeLoader(Extractor): family = "SmokeLoader" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/MACO/Socks5Systemz.py b/modules/parsers/MACO/Socks5Systemz.py index 21605e5c..e750ac71 100644 --- a/modules/parsers/MACO/Socks5Systemz.py +++ b/modules/parsers/MACO/Socks5Systemz.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.core.Socks5Systemz import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.Socks5Systemz import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -12,8 +12,13 @@ def convert_to_MACO(raw_config: dict): parsed_result = MACOModel( family="Socks5Systemz", other=raw_config, - http=[MACOModel.Http(hostname=c2, usage="c2") for c2 in raw_config.get("C2s", [])] - + [MACOModel.Http(hostname=decoy, usage="decoy") for decoy in raw_config.get("Dummy domain", [])], + http=[ + MACOModel.Http(hostname=c2, usage="c2") for c2 in raw_config.get("C2s", []) + ] + + [ + MACOModel.Http(hostname=decoy, usage="decoy") + for decoy in raw_config.get("Dummy domain", []) + ], ) return parsed_result @@ -24,7 +29,7 @@ class Socks5Systemz(Extractor): family = "Socks5Systemz" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/SparkRAT.py b/modules/parsers/MACO/SparkRAT.py index 98707ff3..de76cd1d 100644 --- a/modules/parsers/MACO/SparkRAT.py +++ b/modules/parsers/MACO/SparkRAT.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.community.SparkRAT import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.SparkRAT import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -14,7 +14,12 @@ def convert_to_MACO(raw_config: dict): url = f"http{'s' if raw_config['secure'] else ''}://{raw_config['host']}:{raw_config['port']}{raw_config['path']}" parsed_result.http.append( - MACOModel.Http(uri=url, hostname=raw_config["host"], port=raw_config["port"], path=raw_config["path"]) + MACOModel.Http( + uri=url, + hostname=raw_config["host"], + port=raw_config["port"], + path=raw_config["path"], + ) ) parsed_result.identifier.append(raw_config["uuid"]) @@ -27,7 +32,7 @@ class SparkRAT(Extractor): family = "SparkRAT" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/SquirrelWaffle.py b/modules/parsers/MACO/SquirrelWaffle.py index b3efa182..2e047349 100644 --- a/modules/parsers/MACO/SquirrelWaffle.py +++ b/modules/parsers/MACO/SquirrelWaffle.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.SquirrelWaffle import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.SquirrelWaffle import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -8,7 +9,9 @@ def convert_to_MACO(raw_config: dict): return None parsed_result = MACOModel( - family="SquirrelWaffle", other=raw_config, http=[MACOModel.Http(uri=c2, usage="c2") for c2 in raw_config["URLs"]] + family="SquirrelWaffle", + other=raw_config, + http=[MACOModel.Http(uri=c2, usage="c2") for c2 in raw_config["URLs"]], ) return parsed_result @@ -19,6 +22,8 @@ class SquirrelWaffle(Extractor): family = "SquirrelWaffle" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/MACO/Stealc.py b/modules/parsers/MACO/Stealc.py index 4f8fd8a6..a31d87d9 100644 --- a/modules/parsers/MACO/Stealc.py +++ b/modules/parsers/MACO/Stealc.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.community.Stealc import RULE_SOURCE, extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.Stealc import RULE_SOURCE, extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -8,7 +9,9 @@ def convert_to_MACO(raw_config: dict): return None parsed_result = MACOModel( - family="Stealc", other=raw_config, http=[MACOModel.Http(uri=c2, usage="c2") for c2 in raw_config["C2"]] + family="Stealc", + other=raw_config, + http=[MACOModel.Http(uri=c2, usage="c2") for c2 in raw_config["C2"]], ) return parsed_result @@ -19,6 +22,8 @@ class Stealc(Extractor): family = "Stealc" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = RULE_SOURCE def run(self, stream, matches): diff --git a/modules/parsers/MACO/Strrat.py b/modules/parsers/MACO/Strrat.py index 34ab90a4..9e315c93 100644 --- a/modules/parsers/MACO/Strrat.py +++ b/modules/parsers/MACO/Strrat.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.Strrat import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.Strrat import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -17,6 +18,7 @@ class Strrat(Extractor): family = "Strrat" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/TSCookie.py b/modules/parsers/MACO/TSCookie.py index de0b07cf..099e2a50 100644 --- a/modules/parsers/MACO/TSCookie.py +++ b/modules/parsers/MACO/TSCookie.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.community.TSCookie import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.TSCookie import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -19,7 +19,7 @@ class TSCookie(Extractor): family = "TSCookie" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/TrickBot.py b/modules/parsers/MACO/TrickBot.py index 761bd870..230a6b3a 100644 --- a/modules/parsers/MACO/TrickBot.py +++ b/modules/parsers/MACO/TrickBot.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.community.TrickBot import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.TrickBot import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -17,6 +18,8 @@ class TrickBot(Extractor): family = "TrickBot" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/MACO/UrsnifV3.py b/modules/parsers/MACO/UrsnifV3.py index 3ea2e9d0..e677ed76 100644 --- a/modules/parsers/MACO/UrsnifV3.py +++ b/modules/parsers/MACO/UrsnifV3.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.core.UrsnifV3 import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.UrsnifV3 import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -19,7 +19,7 @@ class UrsnifV3(Extractor): family = "UrsnifV3" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/VenomRat.py b/modules/parsers/MACO/VenomRat.py index a414e4bc..ebbc6f01 100644 --- a/modules/parsers/MACO/VenomRat.py +++ b/modules/parsers/MACO/VenomRat.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.community.VenomRAT import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.VenomRAT import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -17,6 +18,7 @@ class VenomRAT(Extractor): family = "VenomRAT" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/WarzoneRAT.py b/modules/parsers/MACO/WarzoneRAT.py index 9ca74a16..fc6b99cb 100644 --- a/modules/parsers/MACO/WarzoneRAT.py +++ b/modules/parsers/MACO/WarzoneRAT.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.WarzoneRAT import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.WarzoneRAT import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -21,6 +22,7 @@ class WarzoneRAT(Extractor): family = "WarzoneRAT" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/XWorm.py b/modules/parsers/MACO/XWorm.py index d66da627..ffd18c2d 100644 --- a/modules/parsers/MACO/XWorm.py +++ b/modules/parsers/MACO/XWorm.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.community.XWorm import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.XWorm import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -19,7 +19,7 @@ class XWorm(Extractor): family = "XWorm" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/XenoRAT.py b/modules/parsers/MACO/XenoRAT.py index 6bc8f8c0..48a9f988 100644 --- a/modules/parsers/MACO/XenoRAT.py +++ b/modules/parsers/MACO/XenoRAT.py @@ -1,8 +1,8 @@ -import os -from cape_parsers.CAPE.community.XenoRAT import extract_config from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.community.XenoRAT import extract_config +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -19,7 +19,7 @@ class XenoRAT(Extractor): family = "XenoRAT" last_modified = "2024-10-26" sharing = "TLP:CLEAR" - yara_rule = open(os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar")).read() + yara_rule = get_YARA_rule(family) def run(self, stream, matches): return convert_to_MACO(extract_config(stream.read())) diff --git a/modules/parsers/MACO/Zloader.py b/modules/parsers/MACO/Zloader.py index ddc68b46..a3641c93 100644 --- a/modules/parsers/MACO/Zloader.py +++ b/modules/parsers/MACO/Zloader.py @@ -1,6 +1,7 @@ -from cape_parsers.CAPE.core.Zloader import extract_config, rule_source from maco.extractor import Extractor from maco.model import ExtractorModel as MACOModel +from cape_parsers.CAPE.core.Zloader import extract_config, rule_source +from modules.parsers.utils import get_YARA_rule def convert_to_MACO(raw_config: dict): @@ -13,7 +14,9 @@ def convert_to_MACO(raw_config: dict): parsed_result.campaign_id = [raw_config["Campaign ID"]] if "RC4 key" in raw_config: - parsed_result.encryption = [MACOModel.Encryption(algorithm="RC4", key=raw_config[:"RC4 key"])] + parsed_result.encryption = [ + MACOModel.Encryption(algorithm="RC4", key=raw_config[:"RC4 key"]) + ] for address in raw_config.get("address", []): parsed_result.http.append(MACOModel.Http(uri=address)) @@ -26,6 +29,8 @@ class Zloader(Extractor): family = "Zloader" last_modified = "2024-10-26" sharing = "TLP:CLEAR" + yara_rule = get_YARA_rule(family) + yara_rule = rule_source def run(self, stream, matches): diff --git a/modules/parsers/__init__.py b/modules/parsers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/modules/parsers/utils.py b/modules/parsers/utils.py new file mode 100644 index 00000000..8a330119 --- /dev/null +++ b/modules/parsers/utils.py @@ -0,0 +1,40 @@ +import os +import requests + +# Raw file download template (default to Github-based raw download URL) +CAPE_RAW_DOWNLOAD_TEMPLATE=os.environ.get("CAPE_RAW_DOWNLOAD_TEMPLATE", + "https://raw.githubusercontent.com/kevoreilly/CAPEv2/refs/heads/master/data/yara/CAPE/{family}.yar") + +def get_YARA_rule(family: str) -> str | None: + root = os.path.join(os.path.dirname(__file__)) + maco_yara_folder = os.path.join(root, "yara") + # Check to see if the rules local to MACO extractors exist (this can be rules cached from a previous run) + if not os.path.exists(os.path.join(root, "yara")): + os.makedirs(maco_yara_folder) + + # YARA rule paths that differ based on relativity to the MACO extractor + maco_yara_path = f"{maco_yara_folder}/{family}.yar" + cape_yara_path = os.path.join(os.path.dirname(__file__).split("/modules", 1)[0], f"data/yara/CAPE/{family}.yar") + + if os.path.exists(maco_yara_path): + # Return rule that seems to be directly related to MACO extractor + with open(maco_yara_path) as f: + return f.read() + # Check to see if the rule exists in a CAPE or CAPE-like directory structure + elif os.path.exists(cape_yara_path): + # Return the content of local YARA rule + with open(cape_yara_path) as f: + return f.read() + + try: + # Local rule doesn't exist, but maybe we can retrieve the corresponding core rule from CAPEv2 + # NOTE: This won't work in an air-gapped environment unless a mirror exists + resp = requests.get(CAPE_RAW_DOWNLOAD_TEMPLATE.format(family=family), timeout=10) + if resp.ok: + # Cache the rule on disk + with open(maco_yara_path, 'w') as f: + f.write(resp.text) + return resp.text + except Exception as e: + # No rule to be found, assume that extractor has proper exception handling or the rule is embedded + return diff --git a/pyproject.toml b/pyproject.toml index 6b1f0ff5..15c17835 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,8 @@ +[project] +name = "CAPESandbox_community" +version = "1.0" +optional-dependencies.maco = ["CAPE-parsers", "maco", "requests"] + [tool.black] line-length = 132 include = "\\.py(_disabled)?$" @@ -6,3 +11,6 @@ include = "\\.py(_disabled)?$" profile = "black" no_lines_before = ["FUTURE", "STDLIB"] line_length = 132 + +[tool.setuptools] +packages = []