How CAPEv2's YARA-Based Configuration Extraction Framework Operates
CAPEv2 uses YARA rules with embedded cape_type metadata to identify malware families, then routes matching samples through specialized parsers (CAPE extractors, DC3-MWCP, or RATDecoders) to extract configuration data such as C2 URLs and encryption keys.
The configuration extraction framework in CAPEv2 (kevoreilly/capev2) provides automated static analysis capabilities that identify malware families and decrypt their command-and-control settings before dynamic execution begins. This system relies on a multi-step pipeline implemented primarily in lib/cuckoo/common/cape_utils.py and lib/cuckoo/common/objects.py, where YARA-based detection triggers specialized configuration parsers.
YARA Scanning and Detection
The File.get_yara() Method
The entry point for CAPEv2's YARA-based configuration extraction framework is the File.get_yara() method defined in lib/cuckoo/common/objects.py (lines 666-688). When a file is processed, the system calls File.get_yara(category="CAPE") to scan the sample against the compiled CAPE YARA rules.
The method performs the following operations:
- Lazy loading: It initializes compiled YARA rules via
File.init_yara()only when first requested. - Execution: It runs the appropriate rule set from
File.yara_rules[category]against the file buffer. - Result construction: For each match, it builds a dictionary containing
name,meta,strings, andaddresses.
The YARA rules used for static configuration extraction contain a critical meta.cape_type field that describes the type of artifact (for example, "SocGholish Payload" or "Emotet Config").
Filtering Detectable Hits with yara_hit_provides_detection()
Not every YARA match triggers configuration parsing. The framework uses File.yara_hit_provides_detection() (lines 332-336 in lib/cuckoo/common/objects.py) to filter relevant hits. This method checks if the cape_type metadata matches the regular expression:
r" (?:payload|config|loader|strings)$"
Only hits whose cape_type ends with "payload", "config", "loader", or "strings" are considered for configuration extraction. This filter prevents unrelated YARA matches from invoking heavy parsers on benign files.
Extracting the CAPE Name
Mapping YARA Hits to Malware Families
Once a detectable YARA hit is identified, CAPEv2 must determine which parser to invoke. The function cape_name_from_yara() in lib/cuckoo/common/cape_utils.py (lines 402-423) extracts the cape name (for example, "SocGholish" or "TrickBot") from the YARA hit metadata.
This function utilizes File.get_cape_name_from_yara_hit(), which strips the suffix ("Payload", "Config", "Loader", or "Strings") from the cape_type string to isolate the malware family name. The function stores the mapping in results["detections2pid"], enabling the system to track which process IDs generated which CAPE detections.
Static Configuration Extraction Pipeline
The static_extraction() Orchestrator
The core workflow of CAPEv2's YARA-based configuration extraction framework is implemented in static_extraction() (lines 667-696 in lib/cuckoo/common/cape_utils.py). This function orchestrates the entire static analysis pipeline:
- YARA scan: Executes
File(path).get_yara(category="CAPE")to identify potential malware families. - Whitelist check: If no YARA hits are found and the filename matches a whitelist (
named_static_extractors), the file is treated as a special-case static extractor. - CAPE name resolution: For each YARA hit, calls
File.get_cape_name_from_yara_hit()to obtain the malware family name. - Parser invocation: Passes the raw file bytes and cape name to
static_config_parsers().
The function returns a dictionary where the top-level key is the cape name and the value is a mapping of configuration fields to lists of extracted values.
Parser Dispatch with static_config_parsers()
The static_config_parsers() function (lines 176-210 in lib/cuckoo/common/cape_utils.py) serves as the dispatcher for configuration parsing logic. This function supports multiple parser families:
- CAPE extractors: Pure-Python parsers shipped with CAPEv2 that target specific malware families.
- DC3-MWCP: Binary-level format detection and extraction framework.
- RATDecoders: Specialized decoders for remote access trojans.
The dispatch logic follows this priority:
- If the cape name matches a loaded CAPE extractor in
cape_malware_parsers, invoke itsextract_configorconfigentry point. - If no CAPE extractor matches and MWCP or RATDecoders are enabled, attempt those parsers in order.
- Normalize all results by converting map objects to plain lists and flattening nested structures into JSON-serializable values.
Code Examples
Extracting Configuration from a File
The simplest way to leverage CAPEv2's YARA-based configuration extraction framework is through the static_extraction() function:
from lib.cuckoo.common.cape_utils import static_extraction
file_path = "/tmp/malicious.exe"
config = static_extraction(file_path)
print(config)
# → {'SocGholish': {'c2': ['http://bad.io'], ...}}
This function internally performs the YARA scan, selects the correct parser based on the cape_type metadata, and returns a ready-to-use dictionary mapping malware families to their configuration data.
Manual YARA Hit Processing
For advanced use cases requiring granular control over the extraction pipeline, you can manually handle YARA hits and feed them to the parsers:
from lib.cuckoo.common.objects import File
from lib.cuckoo.common.cape_utils import static_config_parsers
f = File("/tmp/malware.bin")
yara_hits = f.get_yara(category="CAPE")
for hit in yara_hits:
cape_name = File.get_cape_name_from_yara_hit(hit)
raw_data = f.file_data
cfg = static_config_parsers(cape_name, f.file_path, raw_data)
if cfg:
print(f"Config for {cape_name}: {cfg}")
break
This low-level approach demonstrates the exact steps performed by static_extraction(), allowing developers to implement custom filtering or preprocessing logic before parser invocation.
Mapping Detections to Process IDs
When analyzing running processes, the framework tracks which YARA detections correspond to specific process IDs:
from lib.cuckoo.common.cape_utils import cape_name_from_yara
from lib.cuckoo.common.objects import File
sample = File("/tmp/sample.bin")
yara_hits = sample.get_yara(category="CAPE")
results = {}
for pid, details in enumerate(sample.get_process_info(), start=1):
cape_name = cape_name_from_yara(details, pid, results)
print(results["detections2pid"])
# → {'1': ['SocGholish'], '3': ['Emotet']}
The cape_name_from_yara() helper records the relationship between process IDs and detected malware families in the detections2pid dictionary, enabling forensic correlation between static configuration extraction and dynamic behavior analysis.
Key Files and Implementation Details
| File | Role | Link |
|---|---|---|
lib/cuckoo/common/objects.py |
Defines the File class, YARA loading (init_yara), scanning (get_yara), and helpers for cape-type detection. |
view on GitHub |
lib/cuckoo/common/cape_utils.py |
Orchestrates static extraction (static_extraction), parser dispatch (static_config_parsers), and cape-name handling (cape_name_from_yara). |
view on GitHub |
modules/signatures/cape_extracted.py |
Example of a signature that consumes the YARA-extracted config and adds it to the analysis report. | view on GitHub |
data/yara/*.yar |
YARA rule set that tags samples with meta.cape_type used by the extraction framework. |
view on GitHub (example) |
web/analysis/views.py |
Renders extracted config in the web UI via the malware_config template tag. |
view on GitHub |
Summary
- YARA rules stored in
data/yara/*.yartag samples withmeta.cape_typemetadata that identifies malware families and artifact types. - The
File.get_yara()method inlib/cuckoo/common/objects.pyexecutes scans and returns structured match data including the criticalcape_typefield. File.yara_hit_provides_detection()filters hits using the regex patternr" (?:payload|config|loader|strings)$"to ensure only relevant matches trigger parsing.static_extraction()inlib/cuckoo/common/cape_utils.pyorchestrates the workflow: scanning, name resolution viacape_name_from_yara(), and parser dispatch viastatic_config_parsers().- The framework supports multiple parser backends including native CAPE extractors, DC3-MWCP, and RATDecoders, normalizing all output into JSON-serializable configuration dictionaries.
- Extracted configurations are attached to analysis reports under
CAPE.configsand rendered in the web interface throughweb/analysis/views.py.
Frequently Asked Questions
How does CAPEv2 determine which parser to use for a given sample?
CAPEv2 extracts the cape_type metadata from YARA rule matches and strips the suffix (such as "Payload" or "Config") to derive the malware family name. This name is passed to static_config_parsers(), which first checks for a matching CAPE extractor in cape_malware_parsers, then falls back to DC3-MWCP or RATDecoders if available.
What YARA metadata field triggers the configuration extraction process?
The framework specifically looks for the cape_type field within YARA rule metadata. Only hits where cape_type matches the regular expression r" (?:payload|config|loader|strings)$" are considered for extraction, preventing unnecessary parsing of benign or unrelated matches.
Can the configuration extraction framework operate without dynamic analysis?
Yes. The static_extraction() function is designed to run entirely during the static analysis phase. It reads the raw file bytes, performs YARA scanning, and invokes the appropriate parsers without requiring the sample to execute in the sandbox environment.
Where are the extracted configurations stored and displayed?
After extraction, configurations are stored in the analysis results dictionary under the CAPE.configs key. The web interface (web/analysis/views.py) renders this data using the malware_config template tag, presenting structured configuration data such as C2 URLs, campaign IDs, and encryption keys alongside dynamic analysis results.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →