From f083adad1095b8ca993c5eaffbf0f4aad30f9bf0 Mon Sep 17 00:00:00 2001 From: Vince Rose Date: Tue, 3 Sep 2024 21:22:25 -0700 Subject: [PATCH 1/6] Reapply "Merge branch 'main' into private-main" This reverts commit 4c3f7766d3c0c2b012da4f7e5926a170527e9e48. --- CHANGELOG.md | 13 +++++++++++++ docs/README.md | 5 +---- empire/server/config.yaml | 4 ++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c663361fc..0096643c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -103,8 +103,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed BypassUACCommand due to compatibility with only Covenant (@Cx01N) ## [5.10.2] - 2024-05-05 +- Updated Starkiller to v2.8.1 ## [5.10.1] - 2024-04-26 +- Updated Starkiller to v2.8.0 ### Added @@ -145,6 +147,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed module generation error in ComputerDetails (@Cx01N) ## [5.9.5] - 2024-02-22 +- Updated Starkiller to v2.7.3 ## [5.9.4] - 2024-02-17 @@ -165,6 +168,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed skywalker exploit (again) and added tests (@Cx01N) ## [5.9.2] - 2024-01-31 +- Updated Starkiller to v2.7.2 ### Fixed @@ -249,6 +253,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed the publishing of docker images to go to the correct DockerHub coordinate (@Vinnybod) ## [5.8.1] - 2023-11-30 +- Updated Starkiller to v2.7.1 ### Added @@ -323,6 +328,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [5.7.3] - 2023-10-17 +- Updated Starkiller to v2.6.1 - Fixed global obfuscation not working on modules (@Cx01N) - Added bypass module in PowerShell to run bypasses after agent is staged (@Cx01N) - Fixed IronPython and Python stagers not getting obfuscation applied (@Cx01N) @@ -355,6 +361,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [5.6.3] - 2023-08-27 +- Updated Starkiller to v2.5.3 - Added Advanced Reporting Plugin and dependencies (@Cx01N) - Pin linters in the workflow - Catch error when starting up database that was seeded by an older version of Empire (@Vinnybod) @@ -386,9 +393,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix changelog link in README (@theguly) ## [5.5.4] - 2023-07-20 +- Updated Starkiller to v2.4.3 ## [5.5.3] - 2023-07-20 +- Updated Starkiller to v2.4.2 - Updated restip message to show IP address on server (@Cx01N) - Fixed onedrive taskings for powershell (@Cx01N) - Update pyyaml to 6.0.1 to avoid build issue from cython (@Vinnybod) @@ -438,6 +447,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [5.4.2] - 2023-06-07 +- Updated Starkiller to v2.3.2 - Fixed python modules not running properly (Cx01N) - Updated python multi_socks to run with Python 3 (Cx01N) @@ -461,6 +471,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [5.2.2] - 2023-04-30 +- Updated Starkiller to v2.2.0 - Dependency upgrades (@Vinnybod) ## [5.2.1] - 2023-04-30 @@ -486,6 +497,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [5.1.2] - 2023-03-29 +- Updated Starkiller to v2.1.1 - Removed thread from IronPython agent (@Hubbl3) - Fixed foreign listener issue with cookies (@Hubbl3) - Fixed error message handling for port forward pivot (@Cx01N) @@ -518,6 +530,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [5.0.3] - 2023-02-20 +- Updated Starkiller to v2.0.5 - Fix Invoke-Kerberoast with etype 17 or 18 (@AdrianVollmer) - Add 3.11 support, bump Dockerfile to 3.11, bump Debian install to 3.8.16 (@Cx01N) - Update the GitHub actions to remove usages of deprecated ::set-output function (@Vinnybod) diff --git a/docs/README.md b/docs/README.md index 883e64314..06e9528bf 100644 --- a/docs/README.md +++ b/docs/README.md @@ -44,10 +44,7 @@ Empire is a post-exploitation and adversary emulation framework that is used to * And Many More ## Sponsors - -       [](https://www.sans.org/cyber-security-courses/red-team-operations-adversary-emulation/) - -      [![](https://user-images.githubusercontent.com/20302208/208271681-235c914b-5359-426e-8a3d-903bbd018847.png)](https://www.cybrary.it/)    +       [](https://www.route4me.com) ## Help us Improve! diff --git a/empire/server/config.yaml b/empire/server/config.yaml index 1825b9db0..d35a3816b 100644 --- a/empire/server/config.yaml +++ b/empire/server/config.yaml @@ -44,10 +44,10 @@ database: ip-blacklist: "" starkiller: enabled: true - repo: git@github.com:BC-SECURITY/Starkiller-Sponsors.git + repo: https://github.com/BC-SECURITY/Starkiller.git directory: empire/server/api/v2/starkiller # Can be a branch, tag, or commit hash - ref: sponsors-main + ref: v2.8.1 auto_update: true submodules: auto_update: true From 19baddb724463499a6ba08feed50192b037aa159 Mon Sep 17 00:00:00 2001 From: Anthony Rose <20302208+Cx01N@users.noreply.github.com> Date: Mon, 9 Sep 2024 23:34:20 -0400 Subject: [PATCH 2/6] Added AC3 sponsor logo (#746) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9e8b85212..ca698e5e7 100644 --- a/README.md +++ b/README.md @@ -53,10 +53,10 @@ Empire is a post-exploitation and adversary emulation framework that is used to
[](https://www.route4me.com//) + + +[](https://www.instagram.com/purpl3_cult/)
- ## Release Notes From dbf87fc755a7526206b46f85b15e3948971163d4 Mon Sep 17 00:00:00 2001 From: Arnaud Rebillout Date: Thu, 19 Sep 2024 13:05:33 +0700 Subject: [PATCH 3/6] Fix various Python 3.12 SyntaxWarning (#748) --- CHANGELOG.md | 2 ++ empire/server/data/agent/ironpython_agent.py | 2 +- .../module_source/python/privesc/linuxprivchecker.py | 10 +++++----- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0096643c7..658f46a7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- Fixed various Python 3.12 SyntaxWarning + ## [5.11.4] - 2024-09-04 ### Added diff --git a/empire/server/data/agent/ironpython_agent.py b/empire/server/data/agent/ironpython_agent.py index 13fdcb04c..15636ea82 100644 --- a/empire/server/data/agent/ironpython_agent.py +++ b/empire/server/data/agent/ironpython_agent.py @@ -1393,7 +1393,7 @@ def run_command(self, command, cmdargs=None): if (-not $($o.User)) { $o = 'N/A' } else { - $o = "$($o.Domain)\$($o.User)" + $o = "$($o.Domain)\\$($o.User)" } } catch { $o = 'N/A' diff --git a/empire/server/data/module_source/python/privesc/linuxprivchecker.py b/empire/server/data/module_source/python/privesc/linuxprivchecker.py index 3b2721966..cf4b8648b 100644 --- a/empire/server/data/module_source/python/privesc/linuxprivchecker.py +++ b/empire/server/data/module_source/python/privesc/linuxprivchecker.py @@ -333,22 +333,22 @@ def search_file_perms(): fdperms = { "WWDIRSROOT": { - "cmd": "find / \( -wholename '/home/homedir*' -prune \) -o \( -type d -perm -0002 \) -exec ls -ld '{}' ';' 2>/dev/null | grep root", + "cmd": r"find / \( -wholename '/home/homedir*' -prune \) -o \( -type d -perm -0002 \) -exec ls -ld '{}' ';' 2>/dev/null | grep root", "msg": "World Writeable Directories for User/Group 'Root'", "results": [], }, "WWDIRS": { - "cmd": "find / \( -wholename '/home/homedir*' -prune \) -o \( -type d -perm -0002 \) -exec ls -ld '{}' ';' 2>/dev/null | grep -v root", + "cmd": r"find / \( -wholename '/home/homedir*' -prune \) -o \( -type d -perm -0002 \) -exec ls -ld '{}' ';' 2>/dev/null | grep -v root", "msg": "World Writeable Directories for Users other than Root", "results": [], }, "WWFILES": { - "cmd": "find / \( -wholename '/home/homedir/*' -prune -o -wholename '/proc/*' -prune \) -o \( -type f -perm -0002 \) -exec ls -l '{}' ';' 2>/dev/null", + "cmd": r"find / \( -wholename '/home/homedir/*' -prune -o -wholename '/proc/*' -prune \) -o \( -type f -perm -0002 \) -exec ls -l '{}' ';' 2>/dev/null", "msg": "World Writable Files", "results": [], }, "SUID": { - "cmd": "find / \( -perm -2000 -o -perm -4000 \) -exec ls -ld {} \; 2>/dev/null", + "cmd": r"find / \( -perm -2000 -o -perm -4000 \) -exec ls -ld {} \; 2>/dev/null", "msg": "SUID/SGID Files and Directories", "results": [], }, @@ -1171,7 +1171,7 @@ def write(self, message): bigline = "=======================================================================================" print(bigline) print( - """ + r""" __ _ ____ _ ________ __ / / (_)___ __ ___ __/ __ \_____(_) __/ ____/ /_ ___ _____/ /_____ _____ / / / / __ \/ / / / |/_/ /_/ / ___/ / | / / / / __ \/ _ \/ ___/ //_/ _ \/ ___/ From 2daeb232c4b6fcd91dc153c57f94315ce210b296 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sun, 22 Sep 2024 19:14:10 +0000 Subject: [PATCH 4/6] Update starkiller version to v2.8.2 --- CHANGELOG.md | 1 + empire/server/config.yaml | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 379331f3e..30172d10b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [5.11.5] - 2024-09-22 +- Updated Starkiller to v2.8.2 - Fixed various Python 3.12 SyntaxWarning diff --git a/empire/server/config.yaml b/empire/server/config.yaml index 1825b9db0..2ce05e548 100644 --- a/empire/server/config.yaml +++ b/empire/server/config.yaml @@ -44,10 +44,10 @@ database: ip-blacklist: "" starkiller: enabled: true - repo: git@github.com:BC-SECURITY/Starkiller-Sponsors.git + repo: https://github.com/BC-SECURITY/Starkiller.git directory: empire/server/api/v2/starkiller # Can be a branch, tag, or commit hash - ref: sponsors-main + ref: v2.8.2 auto_update: true submodules: auto_update: true From 9617a16157dea59ce7aec4a1715cce686d3455b5 Mon Sep 17 00:00:00 2001 From: Vincent Rose Date: Sun, 22 Sep 2024 12:14:44 -0700 Subject: [PATCH 5/6] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30172d10b..d106dd561 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,8 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [5.11.5] - 2024-09-22 -- Updated Starkiller to v2.8.2 +- Updated Starkiller to v2.8.2 - Fixed various Python 3.12 SyntaxWarning ## [5.11.4] - 2024-09-04 From 54ce4187635365d7285fb4cc84669b65bfe60ea5 Mon Sep 17 00:00:00 2001 From: Antonio Date: Sat, 7 Dec 2024 23:20:23 +0100 Subject: [PATCH 6/6] Support Empire for system-wide deployment (#757) --- .github/cst-config-docker.yaml | 3 - .../cst-config-install-base.yaml | 3 - CHANGELOG.md | 4 + Dockerfile | 4 +- docs/quickstart/configuration/client.md | 2 + docs/quickstart/configuration/server.md | 2 + empire.py | 5 +- empire/client/src/EmpireCliConfig.py | 5 +- empire/config_manager.py | 122 ++++++++++++++++++ empire/server/core/config.py | 44 +++++-- empire/server/modules/bof/nanodump.py | 3 +- empire/server/server.py | 18 +-- empire/test/test_zz_reset.py | 8 +- setup/install.sh | 3 - 14 files changed, 173 insertions(+), 53 deletions(-) create mode 100644 empire/config_manager.py diff --git a/.github/cst-config-docker.yaml b/.github/cst-config-docker.yaml index 195bdef20..7f268c26f 100644 --- a/.github/cst-config-docker.yaml +++ b/.github/cst-config-docker.yaml @@ -48,9 +48,6 @@ fileExistenceTests: - name: 'profiles' path: '/empire/empire/server/data/profiles/' shouldExist: true - - name: 'invoke obfuscation' - path: '/usr/local/share/powershell/Modules/Invoke-Obfuscation/' - shouldExist: true - name: 'sharpire' path: '/empire/empire/server/csharp/Covenant/Data/ReferenceSourceLibraries/Sharpire' shouldExist: true diff --git a/.github/install_tests/cst-config-install-base.yaml b/.github/install_tests/cst-config-install-base.yaml index d79acc82a..61bcbb77d 100644 --- a/.github/install_tests/cst-config-install-base.yaml +++ b/.github/install_tests/cst-config-install-base.yaml @@ -71,9 +71,6 @@ fileExistenceTests: - name: 'profiles' path: '/empire/empire/server/data/profiles/' shouldExist: true - - name: 'invoke obfuscation' - path: '/usr/local/share/powershell/Modules/Invoke-Obfuscation/' - shouldExist: true - name: 'sharpire' path: '/empire/empire/server/csharp/Covenant/Data/ReferenceSourceLibraries/Sharpire' shouldExist: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d592319d..9ec54468e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- Support Empire for system-wide deployment (@D3vil0p3r) +- Paths specified in config.yaml where user does not have write permission will be fallback to ~/.empire directory and config.yaml updated as well (@D3vil0p3r) +- Invoke-Obfuscation is no longer copied to /usr/local/share + ## [5.11.7] - 2024-11-11 - Fix arm installs by installing dotnet and powershell manually diff --git a/Dockerfile b/Dockerfile index 61fdf3e43..65fd89ca9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -59,9 +59,7 @@ RUN poetry config virtualenvs.create false && \ COPY . /empire -RUN mkdir -p /usr/local/share/powershell/Modules && \ - cp -r ./empire/server/data/Invoke-Obfuscation /usr/local/share/powershell/Modules && \ - rm -rf /empire/empire/server/data/empire* +RUN rm -rf /empire/empire/server/data/empire* RUN sed -i 's/use: mysql/use: sqlite/g' empire/server/config.yaml && \ sed -i 's/auto_update: true/auto_update: false/g' empire/server/config.yaml diff --git a/docs/quickstart/configuration/client.md b/docs/quickstart/configuration/client.md index 22d0f294f..393f10ee9 100644 --- a/docs/quickstart/configuration/client.md +++ b/docs/quickstart/configuration/client.md @@ -5,6 +5,8 @@ The Client configuration is managed via [empire/client/config.yaml](https://github.com/BC-SECURITY/Empire/blob/master/empire/client/config.yaml). +Once launched, Empire checks for user write permissions on paths specified in `config.yaml`. If the current user does not have write permissions on these paths, `~/.empire` will be set as fallback parent directory and the configuration file will be updated as well. + * **servers** - The servers block is meant to give the user the ability to set up frequently used Empire servers. If a server is listed in this block then when connecting to the server they need only type: `connect -c localhost`. diff --git a/docs/quickstart/configuration/server.md b/docs/quickstart/configuration/server.md index e6c0a9c44..4e00381ee 100644 --- a/docs/quickstart/configuration/server.md +++ b/docs/quickstart/configuration/server.md @@ -2,6 +2,8 @@ The Server configuration is managed via [empire/server/config.yaml](https://github.com/BC-SECURITY/Empire/blob/master/empire/client/config.yaml). +Once launched, Empire checks for user write permissions on paths specified in `config.yaml`. If the current user does not have write permissions on these paths, `~/.empire` will be set as fallback parent directory and the configuration file will be updated as well. + * **suppress-self-cert-warning** - Suppress the http warnings when launching an Empire instance that uses a self-signed cert. * **api** - Configure the RESTful API. This includes the port to run the API on, as well as the path for the SSL certificates. If `empire-priv.key` and `empire-chain.pem` are not found in this directory, self-signed certs will be generated. diff --git a/empire.py b/empire.py index a9687dec4..9c199f719 100644 --- a/empire.py +++ b/empire.py @@ -2,10 +2,11 @@ import sys -from empire import arguments +from empire import arguments, config_manager if __name__ == "__main__": args = arguments.args + config_manager.config_init() if args.subparser_name == "server": from empire.server import server @@ -16,7 +17,7 @@ from empire.scripts.sync_starkiller import sync_starkiller - with open("empire/server/config.yaml") as f: + with open(config_manager.CONFIG_SERVER_PATH) as f: config = yaml.safe_load(f) sync_starkiller(config) diff --git a/empire/client/src/EmpireCliConfig.py b/empire/client/src/EmpireCliConfig.py index 10efeaa28..9029ebb71 100644 --- a/empire/client/src/EmpireCliConfig.py +++ b/empire/client/src/EmpireCliConfig.py @@ -3,6 +3,8 @@ import yaml +from empire import config_manager + log = logging.getLogger(__name__) @@ -15,7 +17,8 @@ def __init__(self): self.set_yaml(location) if len(self.yaml.items()) == 0: log.info("Loading default config") - self.set_yaml("./empire/client/config.yaml") + self.set_yaml(config_manager.CONFIG_CLIENT_PATH) + config_manager.check_config_permission(self.yaml, "client") def set_yaml(self, location: str): try: diff --git a/empire/config_manager.py b/empire/config_manager.py new file mode 100644 index 000000000..5f172133c --- /dev/null +++ b/empire/config_manager.py @@ -0,0 +1,122 @@ +import logging +import os +import shutil +from pathlib import Path + +import yaml + +log = logging.getLogger(__name__) + +user_home = Path.home() +SOURCE_CONFIG_CLIENT = Path("empire/client/config.yaml") +SOURCE_CONFIG_SERVER = Path("empire/server/config.yaml") +CONFIG_DIR = user_home / ".empire" +CONFIG_CLIENT_PATH = CONFIG_DIR / "client" / "config.yaml" +CONFIG_SERVER_PATH = CONFIG_DIR / "server" / "config.yaml" + + +def config_init(): + CONFIG_CLIENT_PATH.parent.mkdir(parents=True, exist_ok=True) + CONFIG_SERVER_PATH.parent.mkdir(parents=True, exist_ok=True) + + if not CONFIG_CLIENT_PATH.exists(): + shutil.copy(SOURCE_CONFIG_CLIENT, CONFIG_CLIENT_PATH) + log.info(f"Copied {SOURCE_CONFIG_CLIENT} to {CONFIG_CLIENT_PATH}") + else: + log.info(f"{CONFIG_CLIENT_PATH} already exists.") + + if not CONFIG_SERVER_PATH.exists(): + shutil.copy(SOURCE_CONFIG_SERVER, CONFIG_SERVER_PATH) + log.info(f"Copied {SOURCE_CONFIG_SERVER} to {CONFIG_SERVER_PATH}") + else: + log.info(f"{CONFIG_SERVER_PATH} already exists.") + + +def check_config_permission(config_dict: dict, config_type: str): + """ + Check if the specified directories in config.yaml are writable. If not, switches to a fallback directory. + Handles both server and client configurations. + + Args: + config_dict (dict): The configuration dictionary loaded from YAML. + config_type (str): The type of configuration ("server" or "client"). + """ + # Define paths to check based on config type + if config_type == "server": + paths_to_check = { + ("api", "cert_path"): config_dict.get("api", {}).get("cert_path"), + ("database", "sqlite", "location"): config_dict.get("database", {}) + .get("sqlite", {}) + .get("location"), + ("starkiller", "directory"): config_dict.get("starkiller", {}).get( + "directory" + ), + ("logging", "directory"): config_dict.get("logging", {}).get("directory"), + ("debug", "last_task", "file"): config_dict.get("debug", {}) + .get("last_task", {}) + .get("file"), + ("directories", "downloads"): config_dict.get("directories", {}).get( + "downloads" + ), + } + config_path = CONFIG_SERVER_PATH # Use the server config path + + elif config_type == "client": + paths_to_check = { + ("logging", "directory"): config_dict.get("logging", {}).get("directory"), + ("directories", "downloads"): config_dict.get("directories", {}).get( + "downloads" + ), + ("directories", "generated-stagers"): config_dict.get( + "directories", {} + ).get("generated-stagers"), + } + config_path = CONFIG_CLIENT_PATH # Use the client config path + + else: + raise ValueError("Invalid config_type. Expected 'server' or 'client'.") + + # Check permissions and update paths as needed + for keys, dir_path in paths_to_check.items(): + if dir_path is None: + continue + + current_dir = dir_path + while current_dir and not os.path.exists(current_dir): + current_dir = os.path.dirname(current_dir) + + if not os.access(current_dir, os.W_OK): + log.info( + "No write permission for %s. Switching to fallback directory.", + current_dir, + ) + user_home = Path.home() + fallback_dir = os.path.join( + user_home, ".empire", str(current_dir).removeprefix("empire/") + ) + + # Update the directory in config_dict + target = config_dict # target is a reference to config_dict + for key in keys[:-1]: + target = target[key] + target[keys[-1]] = fallback_dir + + log.info( + "Updated %s to fallback directory: %s", "->".join(keys), fallback_dir + ) + + # Write the updated configuration back to the correct YAML file + with open(config_path, "w") as config_file: + yaml.safe_dump(paths2str(config_dict), config_file) + + return config_dict + + +def paths2str(data): + if isinstance(data, dict): + return {key: paths2str(value) for key, value in data.items()} + if isinstance(data, list): + return [paths2str(item) for item in data] + if isinstance(data, Path): + return str(data) + return data diff --git a/empire/server/core/config.py b/empire/server/core/config.py index 539c56c87..46eea3f51 100644 --- a/empire/server/core/config.py +++ b/empire/server/core/config.py @@ -5,6 +5,8 @@ import yaml from pydantic import BaseModel, ConfigDict, Field, field_validator +from empire import config_manager + log = logging.getLogger(__name__) @@ -74,9 +76,9 @@ def __getitem__(self, key): class DirectoriesConfig(EmpireBaseModel): - downloads: Path - module_source: Path - obfuscated_module_source: Path + downloads: Path = Path("empire/server/downloads") + module_source: Path = Path("empire/server/modules") + obfuscated_module_source: Path = Path("empire/server/data/obfuscated_module_source") class LoggingConfig(EmpireBaseModel): @@ -99,17 +101,26 @@ class EmpireConfig(EmpireBaseModel): alias="supress-self-cert-warning", default=True ) api: ApiConfig | None = ApiConfig() - starkiller: StarkillerConfig - submodules: SubmodulesConfig - database: DatabaseConfig + starkiller: StarkillerConfig = StarkillerConfig() + submodules: SubmodulesConfig = SubmodulesConfig() + database: DatabaseConfig = DatabaseConfig( + sqlite=SQLiteDatabaseConfig(), + mysql=MySQLDatabaseConfig(), + defaults=DatabaseDefaultsConfig(), + ) plugins: dict[str, dict[str, str]] = {} - directories: DirectoriesConfig - logging: LoggingConfig - debug: DebugConfig + directories: DirectoriesConfig = DirectoriesConfig() + logging: LoggingConfig = LoggingConfig() + debug: DebugConfig = DebugConfig(last_task=LastTaskConfig()) model_config = ConfigDict(extra="allow") - def __init__(self, config_dict: dict): + def __init__(self, config_dict: dict | None = None): + if config_dict is None: + config_dict = {} + if not isinstance(config_dict, dict): + raise ValueError("config_dict must be a dictionary") + super().__init__(**config_dict) # For backwards compatibility self.yaml = config_dict @@ -126,13 +137,18 @@ def set_yaml(location: str): log.warning(exc) -config_dict = {} +config_dict = EmpireConfig().model_dump() if "--config" in sys.argv: location = sys.argv[sys.argv.index("--config") + 1] log.info(f"Loading config from {location}") - config_dict = set_yaml(location) -if len(config_dict.items()) == 0: + loaded_config = set_yaml(location) + if loaded_config: + config_dict = loaded_config +elif config_manager.CONFIG_SERVER_PATH.exists(): log.info("Loading default config") - config_dict = set_yaml("./empire/server/config.yaml") + loaded_config = set_yaml(config_manager.CONFIG_SERVER_PATH) + if loaded_config: + config_dict = loaded_config + config_dict = config_manager.check_config_permission(config_dict, "server") empire_config = EmpireConfig(config_dict) diff --git a/empire/server/modules/bof/nanodump.py b/empire/server/modules/bof/nanodump.py index 30d635115..c214234b8 100644 --- a/empire/server/modules/bof/nanodump.py +++ b/empire/server/modules/bof/nanodump.py @@ -16,8 +16,7 @@ def generate( module=module, params=params, obfuscate=obfuscate ) - for name in params: - value = params[name] + for name, value in params.items(): if name == "write": if value != "": dump_path = value diff --git a/empire/server/server.py b/empire/server/server.py index bfeb69cd2..01287e692 100755 --- a/empire/server/server.py +++ b/empire/server/server.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 import logging import os -import pathlib import pwd import shutil import signal @@ -67,10 +66,6 @@ def setup_logging(args): CSHARP_DIR_BASE = os.path.join(os.path.dirname(__file__), "csharp/Covenant") -INVOKE_OBFS_SRC_DIR_BASE = os.path.join( - os.path.dirname(__file__), "data/Invoke-Obfuscation" -) -INVOKE_OBFS_DST_DIR_BASE = "/usr/local/share/powershell/Modules/Invoke-Obfuscation" def reset(): @@ -94,16 +89,6 @@ def reset(): if os.path.exists(empire_config.starkiller.directory): shutil.rmtree(empire_config.starkiller.directory) - # invoke obfuscation - if os.path.exists(f"{INVOKE_OBFS_DST_DIR_BASE}"): - shutil.rmtree(INVOKE_OBFS_DST_DIR_BASE) - pathlib.Path(pathlib.Path(INVOKE_OBFS_SRC_DIR_BASE).parent).mkdir( - parents=True, exist_ok=True - ) - shutil.copytree( - INVOKE_OBFS_SRC_DIR_BASE, INVOKE_OBFS_DST_DIR_BASE, dirs_exist_ok=True - ) - file_util.remove_file("data/sessions.csv") file_util.remove_file("data/credentials.csv") file_util.remove_file("data/master.log") @@ -144,6 +129,9 @@ def check_submodules(): def fetch_submodules(): + if not os.path.exists(Path(".git")): + log.info("No .git directory found. Skipping submodule fetch.") + return command = ["git", "submodule", "update", "--init", "--recursive"] run_as_user(command) diff --git a/empire/test/test_zz_reset.py b/empire/test/test_zz_reset.py index a3c7dbfe1..da047377d 100644 --- a/empire/test/test_zz_reset.py +++ b/empire/test/test_zz_reset.py @@ -39,8 +39,6 @@ def test_reset_server(monkeypatch, tmp_path, default_argv, server_config_dict): 1. Deletes the sqlite db. Don't need to test mysql atm. 2. Deletes the downloads dir contents 3. Deletes the csharp generated files - 4. Deletes the obfuscated modules - 5. Deletes / Copies invoke obfuscation """ monkeypatch.setattr("builtins.input", lambda _: "y") sys.argv = [*default_argv.copy(), "--reset"] @@ -64,9 +62,8 @@ def test_reset_server(monkeypatch, tmp_path, default_argv, server_config_dict): for f in download_files: assert Path(downloads_dir + f[0]).exists() - # Change the csharp and Invoke-Obfuscation dir so we don't delete real files. + # Change the csharp dir so we don't delete real files. csharp_dir = tmp_path / "empire/server/data/csharp" - invoke_obfs_dir = tmp_path / "powershell/Modules/Invoke-Obfuscation" # Write files to csharp_dir csharp_files = [ @@ -105,7 +102,6 @@ def test_reset_server(monkeypatch, tmp_path, default_argv, server_config_dict): assert Path(server_config_dict["database"]["location"]).exists() server.CSHARP_DIR_BASE = csharp_dir - server.INVOKE_OBFS_DST_DIR_BASE = invoke_obfs_dir with pytest.raises(SystemExit): server.run(args) @@ -126,8 +122,6 @@ def test_reset_server(monkeypatch, tmp_path, default_argv, server_config_dict): csharp_dir / "Data/Tasks/CSharp/Compiled/netcoreapp3.0" / f[0] ).exists() - assert Path(invoke_obfs_dir / "Invoke-Obfuscation.ps1").exists() - if server_config_dict.get("database", {}).get("type") == "sqlite": assert not Path(server_config_dict["database"]["location"]).exists() diff --git a/setup/install.sh b/setup/install.sh index 7eeeace3c..28c3c4c6a 100755 --- a/setup/install.sh +++ b/setup/install.sh @@ -40,9 +40,6 @@ function install_powershell() { sudo tar zxf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/7 sudo chmod +x /opt/microsoft/powershell/7/pwsh sudo ln -s /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh - - sudo mkdir -p /usr/local/share/powershell/Modules - sudo cp -r "$PARENT_PATH"/empire/server/data/Invoke-Obfuscation /usr/local/share/powershell/Modules } function install_mysql() {