diff --git a/bbot/core/helpers/depsinstaller/installer.py b/bbot/core/helpers/depsinstaller/installer.py index 5bea5f508a..ffb7e2fb12 100644 --- a/bbot/core/helpers/depsinstaller/installer.py +++ b/bbot/core/helpers/depsinstaller/installer.py @@ -196,7 +196,7 @@ async def install_module(self, module): deps_common = preloaded["deps"]["common"] if deps_common: for dep_common in deps_common: - if self.setup_status.get(dep_common, False) is True: + if self.setup_status.get(dep_common, False) is True and self.deps_behavior != "force_install": log.debug( f'Skipping installation of dependency "{dep_common}" for module "{module}" since it is already installed' ) diff --git a/bbot/core/helpers/misc.py b/bbot/core/helpers/misc.py index a5bc8a2fca..0230e6f249 100644 --- a/bbot/core/helpers/misc.py +++ b/bbot/core/helpers/misc.py @@ -1300,7 +1300,7 @@ def make_netloc(host, port=None): return f"{host}:{port}" -def which(*executables): +def which(*executables, path=None): """Finds the full path of the first available executable from a list of executables. Args: @@ -1316,7 +1316,7 @@ def which(*executables): import shutil for e in executables: - location = shutil.which(e) + location = shutil.which(e, path=path) if location: return location diff --git a/bbot/core/shared_deps.py b/bbot/core/shared_deps.py index cd338093fc..013a8b4d67 100644 --- a/bbot/core/shared_deps.py +++ b/bbot/core/shared_deps.py @@ -108,6 +108,24 @@ "when": "ansible_facts['os_family'] == 'Debian'", "ignore_errors": True, }, + { + "name": "Get latest Chromium version (Darwin x86_64)", + "uri": { + "url": "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Mac%2FLAST_CHANGE?alt=media", + "return_content": True, + }, + "register": "chromium_version_darwin_x86_64", + "when": "ansible_facts['os_family'] == 'Darwin' and ansible_facts['architecture'] == 'x86_64'", + }, + { + "name": "Get latest Chromium version (Darwin arm64)", + "uri": { + "url": "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Mac_Arm%2FLAST_CHANGE?alt=media", + "return_content": True, + }, + "register": "chromium_version_darwin_arm64", + "when": "ansible_facts['os_family'] == 'Darwin' and ansible_facts['architecture'] == 'arm64'", + }, { "name": "Download Chromium (Debian)", "unarchive": { @@ -119,6 +137,26 @@ "when": "ansible_facts['os_family'] == 'Debian'", "ignore_errors": True, }, + { + "name": "Download Chromium (Darwin x86_64)", + "unarchive": { + "src": "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Mac%2F{{ chromium_version_darwin_x86_64.content }}%2Fchrome-mac.zip?alt=media", + "remote_src": True, + "dest": "#{BBOT_TOOLS}", + "creates": "#{BBOT_TOOLS}/chrome-mac", + }, + "when": "ansible_facts['os_family'] == 'Darwin' and ansible_facts['architecture'] == 'x86_64'", + }, + { + "name": "Download Chromium (Darwin arm64)", + "unarchive": { + "src": "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Mac_Arm%2F{{ chromium_version_darwin_arm64.content }}%2Fchrome-mac.zip?alt=media", + "remote_src": True, + "dest": "#{BBOT_TOOLS}", + "creates": "#{BBOT_TOOLS}/chrome-mac", + }, + "when": "ansible_facts['os_family'] == 'Darwin' and ansible_facts['architecture'] == 'arm64'", + }, # Because Ubuntu is a special snowflake, we have to bend over backwards to fix the chrome sandbox # see https://chromium.googlesource.com/chromium/src/+/main/docs/security/apparmor-userns-restrictions.md { diff --git a/bbot/modules/gowitness.py b/bbot/modules/gowitness.py index 6e3b2e19eb..ec1199bd37 100644 --- a/bbot/modules/gowitness.py +++ b/bbot/modules/gowitness.py @@ -2,6 +2,7 @@ import asyncio import aiosqlite import multiprocessing +import platform from pathlib import Path from contextlib import suppress from shutil import copyfile, copymode @@ -23,6 +24,7 @@ class gowitness(BaseModule): "output_path": "", "social": False, "idle_timeout": 1800, + "chrome_path": "", } options_desc = { "version": "Gowitness version", @@ -33,6 +35,7 @@ class gowitness(BaseModule): "output_path": "Where to save screenshots", "social": "Whether to screenshot social media webpages", "idle_timeout": "Skip the current gowitness batch if it stalls for longer than this many seconds", + "chrome_path": "Path to chrome executable", } deps_common = ["chromium"] deps_pip = ["aiosqlite"] @@ -67,29 +70,54 @@ async def setup(self): self.base_path = Path(output_path) / "gowitness" else: self.base_path = self.scan.home / "gowitness" + self.chrome_path = None - custom_chrome_path = self.helpers.tools_dir / "chrome-linux" / "chrome" - if custom_chrome_path.is_file(): - self.chrome_path = custom_chrome_path + config_chrome_path = self.config.get("chrome_path") + if config_chrome_path: + config_chrome_path = Path(config_chrome_path) + if not config_chrome_path.is_file(): + return False, f"Could not find custom Chrome path at {config_chrome_path}" + self.chrome_path = config_chrome_path + else: + if platform.system() == "Darwin": + bbot_chrome_path = ( + self.helpers.tools_dir / "chrome-mac" / "Chromium.app" / "Contents" / "MacOS" / "Chromium" + ) + else: + bbot_chrome_path = self.helpers.tools_dir / "chrome-linux" / "chrome" + if bbot_chrome_path.is_file(): + self.chrome_path = bbot_chrome_path + + # make sure our chrome path works + chrome_test_pass = False + if self.chrome_path and self.chrome_path.is_file(): + chrome_test_proc = await self.run_process([str(self.chrome_path), "--version"]) + if getattr(chrome_test_proc, "returncode", 1) == 0: + self.verbose(f"Found chrome executable at {self.chrome_path}") + chrome_test_pass = True + + if not chrome_test_pass: + # last resort - try to find a working chrome install + for binary in ("Google Chrome", "chrome", "chromium", "chromium-browser"): + binary_path = self.helpers.which(binary) + if binary_path and Path(binary_path).is_file(): + chrome_test_proc = await self.run_process([str(binary_path), "--version"]) + if getattr(chrome_test_proc, "returncode", 1) == 0: + self.verbose(f"Found chrome executable at {binary_path}") + chrome_test_pass = True + break + + if not chrome_test_pass: + return ( + False, + "Failed to set up Google chrome. Please install manually and set `chrome_path`, or try again with --force-deps.", + ) # fix ubuntu-specific sandbox bug chrome_devel_sandbox = self.helpers.tools_dir / "chrome-linux" / "chrome_sandbox" if chrome_devel_sandbox.is_file(): os.environ["CHROME_DEVEL_SANDBOX"] = str(chrome_devel_sandbox) - # make sure we have a working chrome install - chrome_test_pass = False - for binary in ("chrome", "chromium", "chromium-browser", custom_chrome_path): - binary_path = self.helpers.which(binary) - if binary_path and Path(binary_path).is_file(): - chrome_test_proc = await self.run_process([binary_path, "--version"]) - if getattr(chrome_test_proc, "returncode", 1) == 0: - self.verbose(f"Found chrome executable at {binary_path}") - chrome_test_pass = True - break - if not chrome_test_pass: - return False, "Failed to set up Google chrome. Please install manually or try again with --force-deps." - self.db_path = self.base_path / "gowitness.sqlite3" self.screenshot_path = self.base_path / "screenshots" self.command = self.construct_command()