Skip to content

Commit 7af8021

Browse files
Add MCP server; support selfextracted API (kevoreilly#2917)
* Add MCP server; support selfextracted API Introduce a FastMCP-based MCP server (web/mcp_server.py) to interact with CAPE via tools for submitting files/URLs, querying tasks, downloading artifacts, and listing machines; add MCP docs (MCP.md) and optional dependency group (pyproject.toml). Add support for downloading "selfextracted" files: new API endpoints and handler (web/apiv2/urls.py, web/apiv2/views.py), default config toggles (conf/default/api.conf.default), and UI entries (web/templates/apiv2/index.html). Implement Windows analyzer reboot persistence/handler (analyzer/windows/analyzer.py) using RunOnce registry key and reboot trigger. Update guest docs with AutoLogon guidance (docs/.../additional_configuration.rst). * Update poetry.lock * Update web/apiv2/views.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update analyzer/windows/analyzer.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Validate hashes, secure submissions, refactor data Add input validation and security hardening plus submission data helper. - MCP.md: update example to run mcp_server via poetry and use /opt/CAPEv2 path. - web/apiv2/views.py: enforce SHA256 format check when iterating extracted files to skip invalid values. - web/mcp_server.py: introduce ALLOWED_SUBMISSION_DIR (env var) and enforce files are submitted only from that directory; sanitize filenames from Content-Disposition with os.path.basename; add _build_submission_data helper to normalize/skip empty values and stringify booleans/ints; replace repeated data population with helper calls across submit_file/submit_url/submit_dlnexec/submit_static; narrow JSON parsing exceptions to json.JSONDecodeError and return clearer security violation messages. * Update mcp_server.py * Update views.py * Update views.py * Add MCP docs and config-driven MCP server Replace legacy MCP.md with a new docs page (docs/book/src/usage/mcp.rst) and add it to the usage index. Extend conf/default/api.conf.default with per-section mcp = no toggles (defaulting to disabled) so MCP tools can be enabled/disabled via config. Refactor web/mcp_server.py to load CAPE config, derive API URL from api.conf when unset, add CAPE root to sys.path, handle imports gracefully, introduce per-request token support and global auth enforcement, and register MCP tools conditionally based on api.conf mcp flags. Also improve download/submission helpers and add token parameters to most tool endpoints. * Update mcp_server.py * Improve MCP auth docs and add auth tools Revise MCP authentication docs to recommend storing CAPE_API_TOKEN in client config (not global env), add clear Local (stdio) vs Remote (SSE) deployment guidance, and document authentication priority. In web/mcp_server.py import additional web_utils helpers, add a startup warning when token auth is enabled but no default token is set, and expose two new MCP tools: `extendedtasksearch` (returns available advanced search terms/filters/hash types) and `verify_auth` (lightweight token validity check using cuckoo status). These changes improve security guidance and provide runtime helpers for building and validating authenticated requests. --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent 7ace953 commit 7af8021

File tree

11 files changed

+1211
-1
lines changed

11 files changed

+1211
-1
lines changed

analyzer/windows/analyzer.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,49 @@ def complete(self):
351351

352352
log.info("Analysis completed")
353353

354+
def handle_reboot(self):
355+
"""Handle system reboot request."""
356+
# We need to persist the analyzer so it runs again after reboot.
357+
# We will use the RunOnce registry key.
358+
359+
# 1. Determine paths
360+
python_path = sys.executable
361+
analyzer_path = os.path.abspath(sys.argv[0])
362+
working_dir = os.getcwd()
363+
364+
# 2. Formulate command
365+
# We use cmd.exe to ensure the working directory is correct.
366+
# cmd /c "cd /d <cwd> && <python> <analyzer>"
367+
command = 'cmd /c "cd /d "{}" && "{}" "{}"'.format(working_dir, python_path, analyzer_path)
368+
369+
# 3. Write to Registry
370+
from lib.common.registry import set_regkey_full
371+
from lib.common.rand import random_string
372+
373+
# Randomize the key name to avoid detection
374+
key_name = random_string(8)
375+
376+
# Determine root key based on privileges
377+
if SHELL32.IsUserAnAdmin():
378+
key_path = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce\\{}".format(key_name)
379+
else:
380+
key_path = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce\\{}".format(key_name)
381+
382+
log.info("Setting reboot persistence: %s -> %s", key_path, command)
383+
try:
384+
set_regkey_full(key_path, "REG_SZ", command)
385+
except Exception as e:
386+
log.error("Failed to set persistence key: %s", e)
387+
return
388+
389+
# 4. Initiate Reboot
390+
log.info("Initiating system reboot")
391+
# Using shutdown command is robust
392+
subprocess.run(["shutdown", "/r", "/t", "0", "/f"], check=False)
393+
394+
# Stop the analysis loop so we don't interfere while shutting down
395+
self.do_run = False
396+
354397
def get_completion_key(self):
355398
return getattr(self.config, "completion_key", "")
356399

@@ -1260,6 +1303,11 @@ def _handle_resume(self, data):
12601303
self.analyzer.LASTINJECT_TIME = timeit.default_timer()
12611304
self._handle_process(data)
12621305

1306+
def _handle_reboot(self, data):
1307+
"""Handle reboot request from the monitor."""
1308+
log.info("Received reboot request from monitored process")
1309+
self.analyzer.handle_reboot()
1310+
12631311
def _handle_shutdown(self, data):
12641312
"""Handle attempted shutdowns/restarts.
12651313

0 commit comments

Comments
 (0)