Skip to content

Commit

Permalink
Merge branch 'Queue_task_timeout' of https://github.com/cccs-mog/CAPEv2
Browse files Browse the repository at this point in the history
… into Queue_task_timeout
  • Loading branch information
cccs-mog committed Sep 27, 2024
2 parents eef05a3 + 132e46d commit 4020041
Show file tree
Hide file tree
Showing 70 changed files with 2,673 additions and 498 deletions.
30 changes: 28 additions & 2 deletions agent/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,20 @@
import multiprocessing
import os
import platform
import random
import shlex
import shutil
import socket
import socketserver
import stat
import string
import subprocess
import sys
import tempfile
import time
import traceback
from io import StringIO
from threading import Lock
from typing import Iterable
from zipfile import ZipFile

Expand All @@ -41,7 +44,7 @@
if sys.maxsize > 2**32 and sys.platform == "win32":
sys.exit("You should install python3 x86! not x64")

AGENT_VERSION = "0.17"
AGENT_VERSION = "0.18"
AGENT_FEATURES = [
"execpy",
"execute",
Expand All @@ -54,6 +57,7 @@

if sys.platform == "win32":
AGENT_FEATURES.append("mutex")
AGENT_FEATURES.append("browser_extension")
MUTEX_TIMEOUT_MS = 500
from ctypes import WinError, windll

Expand Down Expand Up @@ -89,6 +93,8 @@ def _missing_(cls, value):
return None


AGENT_BROWSER_EXT_PATH = ""
AGENT_BROWSER_LOCK = Lock()
ANALYZER_FOLDER = ""
agent_mutexes = {}
"""Holds handles of mutexes held by the agent."""
Expand Down Expand Up @@ -196,7 +202,7 @@ def handle(self, obj):
if "client_ip" in state and request.client_ip != state["client_ip"]:
if request.client_ip != "127.0.0.1":
return
if obj.path != "/status" or request.method != "POST":
if obj.path not in ["/status", "/browser_extension"] or request.method != "POST":
return

for route, fn in self.routes[obj.command]:
Expand Down Expand Up @@ -753,6 +759,26 @@ def do_execpy():
return json_exception(f"Error executing Python command: {ex}")


@app.route("/browser_extension", methods=["POST"])
def do_browser_ext():
global AGENT_BROWSER_EXT_PATH
AGENT_BROWSER_LOCK.acquire()
if not AGENT_BROWSER_EXT_PATH:
try:
ext_tmpdir = tempfile.mkdtemp(prefix="tmp")
except Exception:
AGENT_BROWSER_LOCK.release()
return json_exception("Error creating temporary directory")
ext_filepath = "bext_" + "".join(random.choice(string.ascii_letters) for _ in range(11)) + ".json"
AGENT_BROWSER_EXT_PATH = os.path.join(ext_tmpdir, ext_filepath)
network_data = request.form.get("networkData")
if network_data:
with open(AGENT_BROWSER_EXT_PATH, "w") as ext_fd:
ext_fd.write(network_data)
AGENT_BROWSER_LOCK.release()
return json_success("OK")


@app.route("/pinning")
def do_pinning():
if "client_ip" in state:
Expand Down
31 changes: 10 additions & 21 deletions analyzer/windows/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,45 +496,34 @@ def run(self):
# Initialize Auxiliary modules
Auxiliary()
prefix = f"{auxiliary.__name__}."

# disable_screens = True
# if self.options.get("disable_screens") == "0":
# disable_screens = False
windows_modules = ("human", "screenshots", "sysmon")

for _, name, _ in pkgutil.iter_modules(auxiliary.__path__, prefix):
try:
log.debug('Importing auxiliary module "%s"...', name)
__import__(name, globals(), locals(), ["dummy"])
# log.debug('Imported auxiliary module "%s"', name)
mod_name = name.split(".")[-1]
if mod_name in windows_modules:
mod_name += "_windows"
# if hasattr(self.config, mod_name) and getattr(self.config, mod_name, False):
# log.debug('Imported auxiliary module "%s"', name)
except ImportError as e:
log.warning('Unable to import the auxiliary module "%s": %s', name, e)

# Walk through the available auxiliary modules.
aux_modules = []

for module in sorted(Auxiliary.__subclasses__(), key=lambda x: x.start_priority, reverse=True):
# Try to start the auxiliary module.
# if module.__name__ == "Screenshots" and disable_screens:
# continue
try:
aux = module(self.options, self.config)
log.debug('Initialized auxiliary module "%s"', module.__name__)
aux_modules.append(aux)

# The following commented out code causes the monitor to not upload logs.
# If the auxiliary module is not enabled, we shouldn't start it
# if hasattr(aux, "enabled") and not getattr(aux, "enabled", False):
# log.debug('Auxiliary module "%s" is disabled.', module.__name__)
# # We continue so that the module is not added to AUX_ENABLED
# continue
# else:
log.debug('Trying to start auxiliary module "%s"...', module.__name__)
log.debug('Trying to start auxiliary module "%s"...', module.__module__)
aux.start()
except (NotImplementedError, AttributeError) as e:
log.warning("Auxiliary module %s was not implemented: %s", module.__name__, e)
except Exception as e:
log.warning("Cannot execute auxiliary module %s: %s", module.__name__, e)
log.warning("Cannot execute auxiliary module %s: %s", module.__module__, e)
else:
log.debug("Started auxiliary module %s", module.__name__)
log.debug("Started auxiliary module %s", module.__module__)
AUX_ENABLED.append(aux)

"""
Expand Down
12 changes: 12 additions & 0 deletions analyzer/windows/data/yara/SlowLoader.yar
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
rule SlowLoader
{
meta:
author = "kevoreilly"
description = "SlowLoader detonation aide for slow cpus (thread race)"
cape_options = "break-on-return=CreateProcessA,action0=sleep:1000,count=0"
packed = "f6eeb73ffb3e6d6cc48f74344cb590614db7e3116ba00a52aefd7dff468a60a5"
strings:
$code = {0F B6 44 07 08 0F B6 54 1F 08 03 C2 25 FF 00 00 80 79 07 48 0D 00 FF FF FF 40 89 45 ?? 6A 00}
condition:
any of them
}
12 changes: 12 additions & 0 deletions analyzer/windows/data/yara/Themida.yar
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
rule Themida
{
meta:
author = "kevoreilly"
description = "Themida detonation shim"
cape_options = "unhook-apis=NtSetInformationThread,force-sleepskip=0"
packed = "6337ff4cf413f56cc6c9a8e67f24b8d7f94f620eae06ac9f0b113b5ba82ea176"
strings:
$code = {FC 31 C9 49 89 CA 31 C0 31 DB AC 30 C8 88 E9 88 D5 88 F2 B6 08 66 D1 EB 66 D1 D8 73 09}
condition:
uint16(0) == 0x5A4D and all of them
}
Binary file modified analyzer/windows/dll/capemon.dll
Binary file not shown.
Binary file modified analyzer/windows/dll/capemon_x64.dll
Binary file not shown.
9 changes: 9 additions & 0 deletions analyzer/windows/lib/common/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@

ARCHIVE_OPTIONS = (OPT_FILE, OPT_PASSWORD)
DLL_OPTIONS = (OPT_ARGUMENTS, OPT_DLLLOADER, OPT_FUNCTION)
SERVICE_OPTIONS = (OPT_SERVICENAME, OPT_SERVICEDESC, OPT_ARGUMENTS)


""" Excel, Word, and Powerpoint won't have macros enabled without interaction for
Expand All @@ -65,3 +66,11 @@
TRUSTED_PATH_TEXT = (
f"Use MS Office Trusted Path location {MSOFFICE_TRUSTED_PATH} unless the user has provided a '{OPT_CURDIR}' option."
)

DLL_OPTION_TEXT = f"""\
Use the '{OPT_DLLLOADER}' option to set the name of the process loading the DLL (defaults to rundll32.exe).
Use the '{OPT_ARGUMENTS}' option to set the arguments to be passed to the exported function(s).
Use the '{OPT_FUNCTION}' option to set the name of the exported function/ordinal to execute.
The default function is '#1'.
Can be multiple function/ordinals split by colon. Ex: function=#1:#3 or #2-4
"""
38 changes: 25 additions & 13 deletions analyzer/windows/lib/common/defines.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org
# See the file 'docs/LICENSE' for copying permission.

import sys
from ctypes import (
POINTER,
WINFUNCTYPE,
Structure,
Union,
c_bool,
Expand All @@ -17,16 +17,20 @@
c_ushort,
c_void_p,
c_wchar_p,
windll,
)

NTDLL = windll.ntdll
KERNEL32 = windll.kernel32
ADVAPI32 = windll.advapi32
USER32 = windll.user32
SHELL32 = windll.shell32
PDH = windll.pdh
PSAPI = windll.psapi
if sys.platform == "win32":
from ctypes import WINFUNCTYPE, windll

NTDLL = windll.ntdll
KERNEL32 = windll.kernel32
ADVAPI32 = windll.advapi32
USER32 = windll.user32
SHELL32 = windll.shell32
PDH = windll.pdh
PSAPI = windll.psapi
EnumWindowsProc = WINFUNCTYPE(c_bool, POINTER(c_int), POINTER(c_int))
EnumChildProc = WINFUNCTYPE(c_bool, POINTER(c_int), POINTER(c_int))

BYTE = c_ubyte
USHORT = c_ushort
Expand Down Expand Up @@ -96,6 +100,7 @@
ERROR_BROKEN_PIPE = 0x0000006D
ERROR_MORE_DATA = 0x000000EA
ERROR_PIPE_CONNECTED = 0x00000217
ERROR_INVALID_HANDLE = 0x00000006

WAIT_TIMEOUT = 0x00000102

Expand Down Expand Up @@ -137,6 +142,17 @@

MAX_PATH = 260

# Button messages
BM_SETCHECK = 0x000000F1
BM_GETCHECK = 0x000000F0
# Button states
BST_UNCHECKED = 0x0000
BST_CHECKED = 0x0001
BST_INDETERMINATE = 0x0002

# Process cannot access the file because it is being used by another process.
ERROR_SHARING_VIOLATION = 0x00000020


class STARTUPINFO(Structure):
_fields_ = [
Expand Down Expand Up @@ -311,7 +327,3 @@ class PDH_FMT_COUNTERVALUE(Structure):
("CStatus", DWORD),
("doubleValue", DOUBLE),
]


EnumWindowsProc = WINFUNCTYPE(c_bool, POINTER(c_int), POINTER(c_int))
EnumChildProc = WINFUNCTYPE(c_bool, POINTER(c_int), POINTER(c_int))
74 changes: 74 additions & 0 deletions analyzer/windows/modules/auxiliary/browsermonitor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Copyright (C) 2024 [email protected]
# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org
# See the file 'docs/LICENSE' for copying permission.
import logging
import os
import subprocess
import tempfile
import time
from threading import Thread

from lib.common.abstracts import Auxiliary
from lib.common.results import upload_to_host

log = logging.getLogger(__name__)


class Browsermonitor(Auxiliary, Thread):
"""Monitors Browser Extension request logs."""

def __init__(self, options=None, config=None):
if options is None:
options = {}
Auxiliary.__init__(self, options, config)
Thread.__init__(self)
self.do_run = False
self.enabled = config.browsermonitor
self.startupinfo = subprocess.STARTUPINFO()
self.startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
self.browser_logfile = ""
self.last_modification = 0.0
self._is_first_save = True

def _find_browser_extension(self):
temp_dir = tempfile.gettempdir()
while not self.browser_logfile and self.do_run:
temp_dir_list = os.listdir(temp_dir)
for directory in temp_dir_list:
tmp_directory_path = os.path.join(temp_dir, directory)
if not os.path.isdir(tmp_directory_path):
continue
if not directory.startswith("tmp"):
continue
tmp_dir_files = os.listdir(tmp_directory_path)
for file in tmp_dir_files:
if file.startswith("bext_") and file.endswith(".json"):
self.browser_logfile = os.path.join(temp_dir, directory, file)
log.debug(f"Found extension logs: {self.browser_logfile}")
break
time.sleep(1)

def _collect_browser_logs(self):
if not self._is_first_save and self.last_modification != os.path.getmtime(self.browser_logfile):
return
self.last_modification = os.path.getmtime(self.browser_logfile)
upload_to_host(self.browser_logfile, "browser/requests.log")
self._is_first_save = False

def run(self):
self.do_run = True
if self.enabled:
self._find_browser_extension()
self.last_modification = os.path.getmtime(self.browser_logfile)
while self.do_run:
self._collect_browser_logs()
time.sleep(1)
return True
return False

def stop(self):
if self.enabled:
self.do_run = False
if self.browser_logfile:
self._collect_browser_logs()
return True
Loading

0 comments on commit 4020041

Please sign in to comment.