Chrysalis DLL Side-Loading and Execution
An attacker has achieved code execution by placing a malicious DLL in the same directory as a legitimate Bluetooth service, exploiting the search order to side-load code and bypass standard system directory protections.
Based on research by Elastic Security Labs 2026-09-20 9 steps · 3 queries T1574.002
Brief
Why now
Attackers continue to use DLL side-loading to bypass security controls by piggybacking on trusted, signed binaries. Recent research from Elastic Security Labs in Benchmarking the Agentic SOC highlights how automated workflows can evaluate complex intrusion patterns like the Chrysalis loader. We designed this hunt to find the structural evidence of that specific side-loading technique.
How the hunt flows
The first phase scopes the environment to find active targets. The query identifies every host currently running the legitimate Bluetooth service executable. This initial filter reduces the data set before we move into more intensive behavioral analysis.
In the second phase, the hunt performs a parallel fan-out to gather evidence. One branch searches for module load events where the DLL resides in the same directory as the service executable, specifically excluding the C:\Windows\System32\ path. A second branch checks for known malicious file hashes associated with the Chrysalis campaign to provide immediate confirmation if a known loader is present.
The third phase uses an automated agent to triage the results. The agent evaluates the directory proximity of the loaded DLLs. It prioritizes the structural relationship between the executable and the library over the specific filename, as attackers can easily rename files to evade simple detections. The agent then assigns a verdict for each host based on the rarity of the module across the fleet.
Finally, the hunt routes the findings for response. If the agent confirms a side-loading intrusion, the playbook prompts for host isolation and forensic preservation of the malicious DLL for further analysis.
What the hunt cannot see
This hunt relies heavily on module load visibility. If the environment lacks Sysmon EID 7 or equivalent telemetry, the side-loading event remains invisible because the process appears to start normally. Additionally, some legitimate applications ship with their own libraries in the same folder. This may create noise that requires an analyst to tune the results by excluding known-good, third-party application paths that do not match the expected Bluetooth service profile.
Steps
-
Scope hosts running the service
Query · scopingIdentify hosts where the targeted Bluetooth service is active to focus the hunt.
reads hb_process_activitysqlSELECT DISTINCT device_hostname, process_path, user_name, time FROM hb_process_activity WHERE LOWER(process_name) LIKE '%{{service_name}}' AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')What a hit looks like. A list of hosts where the Bluetooth service is running. If empty, the service is not active in the scope.
-
Analyze directory-proximity module loads
Query · detection candidateFind modules loaded from the same directory as the service, excluding standard Windows system paths.
reads hb_module_activitysqlSELECT device_hostname, process_name, module_path, module_name, COUNT(DISTINCT device_hostname) AS hosts, MIN(time) AS first_seen FROM hb_module_activity WHERE LOWER(process_name) LIKE '%{{service_name}}' AND REPLACE(LOWER(module_path), LOWER(module_name), '') = REPLACE(LOWER(process_name), LOWER('{{service_name}}'), '') AND LOWER(module_path) NOT LIKE 'c:\windows\system32\%' AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY 1, 2, 3, 4 HAVING hosts <= 3What a hit looks like. A module loaded from the same application folder as BluetoothService.exe. Rarity across the fleet increases suspicion.
-
Enrich with known malicious hashes
Query · enrichmentCheck if any files touched on the scoped hosts match reported malicious indicators like the EICAR test hash.
reads hb_file_activitysqlSELECT device_hostname, file_name, file_path, file_hash_sha256, time FROM hb_file_activity WHERE instr(',' || '{{malicious_hashes}}' || ',', ',' || LOWER(file_hash_sha256) || ',') > 0 AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')What a hit looks like. File activity matching known malicious hashes. This confirms the presence of the expected loader.
-
Analyze side-loading evidence
Agent triageEvaluate whether the combination of directory proximity and module rarity indicates a successful Chrysalis side-load.
-
Route on triage verdict
DecisionDetermine next steps based on whether the agent confirmed a side-loading intrusion.
-
Isolate compromised host
Response actionContain the backdoor by isolating the affected endpoint from the network.
-
Forensic verification
Analyst taskConfirm the agent's findings and extract the malicious DLL for further analysis.
-
Documentation and close out
Analyst taskRecord the results and tuning notes to prevent recurrence.
Coverage
Scenario coverage
| Stage | Covered | How, or why not |
|---|---|---|
| DLL Side-loading via Bluetooth Service T1574.002 |
Yes | scoping-hosts, rare-module-load |
| Malicious Loader Execution T1574.002 |
Yes | malicious-hash-check, triage-agent |
Blind spots
- Needs hb_module_activity with Sysmon EID 7. Without module load events, a side-load appears as a normal service execution, leaving the intrusion completely invisible. It would answer whether a module was loaded into the service process from its local folder.
- Needs precise directory filtering. Excluding System32 is necessary but may still produce false positives if the application regularly uses its own path for shared libraries. It would answer if the service intentionally loads legitimate modules from non-standard paths.
Parameters & data
Parameters
| Parameter | Type | Default | What it is |
|---|---|---|---|
lookback_days | number | 14 | Days of history to examine. |
malicious_hashes | list[hash] | 275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f | Known-malicious hashes from the research, including the EICAR test hash. |
scope_hosts | list[host] | — | Optional list of hostnames to narrow the scope. |
service_name | string | bluetoothservice.exe | The legitimate executable targeted for side-loading. |
Telemetry
| Source | Category | Telemetry |
|---|---|---|
| Endpoint telemetry (hb_ surfaces) | endpoint | endpoint |
Source
---
analysis: A static rule for log.dll is easily bypassed. This hunt uses structural
directory comparison and fleet-wide rarity to identify the core behavior of side-loading
regardless of the DLL filename.
blind_spots:
- id: missing-module-visibility
question: whether a module was loaded into the service process from its local folder
requires: hb_module_activity with Sysmon EID 7
risk: Without module load events, a side-load appears as a normal service execution,
leaving the intrusion completely invisible.
stage: dll-side-loading-bluetooth
- id: system32-noise
question: if the service intentionally loads legitimate modules from non-standard
paths
requires: precise directory filtering
risk: Excluding System32 is necessary but may still produce false positives if the
application regularly uses its own path for shared libraries.
stage: dll-side-loading-bluetooth
coverage:
- stage: dll-side-loading-bluetooth
status: covered
steps:
- scoping-hosts
- rare-module-load
- stage: malicious-loader-execution
status: covered
steps:
- malicious-hash-check
- triage-agent
guardrails:
claims: no_unsupported
evidence: citation_required
missing_data: not_benign
telemetry: untrusted
hunt:
applicability: campaign-specific
handoff: promote-to-detection
justification: Side-loading bypasses traditional binary reputation checks and path-based
execution policies by piggybacking on a trusted, signed service binary.
methodology: model-assisted
trigger: intel-report
hypothesis: An attacker has achieved code execution by placing a malicious DLL in
the same directory as a legitimate Bluetooth service, exploiting the search order
to side-load code and bypass standard system directory protections.
labels:
- hunt
- attack.t1574.002
name: Chrysalis DLL Side-Loading and Execution
parameters:
lookback_days:
default: '14'
description: Days of history to examine.
type: number
malicious_hashes:
default:
- 275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f
description: Known-malicious hashes from the research, including the EICAR test
hash.
from:
kind: article
observed: '2026-08-04'
ref: Elastic Security Labs
type: list[hash]
scope_hosts:
default: []
description: Optional list of hostnames to narrow the scope.
type: list[host]
service_name:
default: bluetoothservice.exe
description: The legitimate executable targeted for side-loading.
type: string
provenance:
authors:
- name: Huntbase hunt generation
org: huntbase.io
generated:
by: huntbase-hunt-generation
from: https://www.elastic.co/security-labs/threat-command/llm-benchmarking-agentic-soc
gates:
- dry-run
- lint
model: hb_google/gemini-3-flash-preview
rationale: Focus on the Windows hosts named srv-win-defend-01 or similar. Ensure the
environment has Sysmon EID 7 enabled for module load visibility.
references:
- name: "Elastic Security Labs \u2014 Benchmarking the Agentic SOC"
url: https://www.elastic.co/security-labs/threat-command/llm-benchmarking-agentic-soc
related:
- hunt: unusual-dll-loads-by-system-services
reason: This hunt is specific to the Chrysalis campaign; a broader hunt would cover
all services loading from non-system directories.
relation: out-of-scope-alternative
scenario:
stages:
- name: DLL Side-loading via Bluetooth Service
observables:
- BluetoothService.exe
- log.dll
- srv-win-defend-01
slug: dll-side-loading-bluetooth
tactic: defense-evasion
techniques:
- T1574.002
- name: Malicious Loader Execution
observables:
- log.dll
- EICAR test file hash
slug: malicious-loader-execution
tactic: execution
techniques:
- T1574.002
summary: The Chrysalis campaign involves a DLL side-loading attack on a Windows
host where a legitimate Bluetooth service loads a malicious DLL. The malicious
loader carries an EICAR test hash, enabling the evaluation of agentic SOC tools
for alert triage, threat hunting, and automated incident response.
severity: high
targets:
analyst:
name: Tier-2 analyst
role: analyst
endpoint:
category: endpoint
name: Endpoint telemetry (hb_ surfaces)
telemetry:
- endpoint
hunter:
agent: true
name: Hunt agent
tlp: clear
type: investigation
---
# Chrysalis DLL Side-Loading and Execution
This hunt identifies the Chrysalis side-loading pattern by searching for instances where BluetoothService.exe loads a module from its own application directory rather than a standard system path. It uses a funnel approach to scope the investigation to hosts running the target service, then fans out to compare module directory proximity and known malicious hash activity. An agent then evaluates the structural evidence of the side-load—prioritizing directory proximity over the filename—to determine the final verdict.
## scoping-hosts
<!-- Scope hosts running the service -->
Identify hosts where the targeted Bluetooth service is active to focus the hunt.
```sqlite target=endpoint role=scoping params=(service_name=service_name, scope_hosts=scope_hosts, lookback_days=lookback_days)
~~~yaml
expected: A list of hosts where the Bluetooth service is running. If empty, the service
is not active in the scope.
reads:
- device_hostname
- process_name
- process_path
- time
- user_name
silence: not_evidence_of_absence
source: hb_process_activity
verified: dry-run
verified_at: '2026-09-20'
~~~
SELECT DISTINCT device_hostname, process_path, user_name, time FROM hb_process_activity WHERE LOWER(process_name) LIKE '%{{service_name}}' AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')
```
## side-loading-fan-out
<!-- Fan-out for behavioral and indicator evidence -->
parallel:
- → rare-module-load
- → malicious-hash-check
join: → triage-agent
## rare-module-load
<!-- Analyze directory-proximity module loads -->
Find modules loaded from the same directory as the service, excluding standard Windows system paths.
```sqlite target=endpoint role=detection-candidate params=(service_name=service_name, scope_hosts=scope_hosts, lookback_days=lookback_days)
~~~yaml
baseline:
compare: first_seen
window: '{{lookback_days}}d'
expected: A module loaded from the same application folder as BluetoothService.exe.
Rarity across the fleet increases suspicion.
prevalence:
by: device_hostname
key:
- module_name
- module_path
rare_below: 3
reads:
- device_hostname
- module_name
- module_path
- process_name
- time
silence: not_evidence_of_absence
source: hb_module_activity
verified: dry-run
verified_at: '2026-09-20'
~~~
SELECT device_hostname, process_name, module_path, module_name, COUNT(DISTINCT device_hostname) AS hosts, MIN(time) AS first_seen FROM hb_module_activity WHERE LOWER(process_name) LIKE '%{{service_name}}' AND REPLACE(LOWER(module_path), LOWER(module_name), '') = REPLACE(LOWER(process_name), LOWER('{{service_name}}'), '') AND LOWER(module_path) NOT LIKE 'c:\windows\system32\%' AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY 1, 2, 3, 4 HAVING hosts <= 3
```
## malicious-hash-check
<!-- Enrich with known malicious hashes -->
Check if any files touched on the scoped hosts match reported malicious indicators like the EICAR test hash.
```sqlite target=endpoint role=enrichment params=(malicious_hashes=malicious_hashes, scope_hosts=scope_hosts, lookback_days=lookback_days)
~~~yaml
expected: File activity matching known malicious hashes. This confirms the presence
of the expected loader.
reads:
- device_hostname
- file_hash_sha256
- file_name
- file_path
- time
silence: not_evidence_of_absence
source: hb_file_activity
verified: dry-run
verified_at: '2026-09-20'
~~~
SELECT device_hostname, file_name, file_path, file_hash_sha256, time FROM hb_file_activity WHERE instr(',' || '{{malicious_hashes}}' || ',', ',' || LOWER(file_hash_sha256) || ',') > 0 AND ('{{scope_hosts}}' = '' OR instr(',' || '{{scope_hosts}}' || ',', ',' || device_hostname || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')
```
## triage-agent
<!-- Analyze side-loading evidence -->
```agent target=hunter
cite: required
context:
- scoping-hosts
- rare-module-load
- malicious-hash-check
max_iterations: 4
objective: Determine if BluetoothService.exe has been subverted via side-loading.
Prioritize the 'directory proximity' of the DLL to the executable as the primary
evidence; treat the specific filename (e.g. log.dll) as secondary. Corroborate with
any matching malicious hashes found in the environment.
success_criteria: A verdict for every host that identifies the specific file and justifies
the side-loading conclusion.
tools:
- endpoint
```
## route-verdict
<!-- Route on triage verdict -->
if~: "the triage verdict is malicious for at least one host based on directory-proximity loading" (confidence: high, judge=hunter)
then: → isolate-host
indeterminate: → forensic-task
unavailable: → forensic-task (blind_spot: missing-module-visibility)
else: → documentation-task
## isolate-host
<!-- Isolate compromised host -->
```action target=endpoint
~~~yaml
approval: required
~~~
Isolate the host and preserve the directory containing the suspected side-loaded DLL for forensic collection.
```
→ forensic-task
## forensic-task
<!-- Forensic verification -->
```manual target=analyst
Manually verify the directory content for BluetoothService.exe. Confirm whether an unauthorized DLL exists in the same folder and extract its hash for cross-referencing.
```
→ documentation-task
## documentation-task
<!-- Documentation and close out -->
```manual target=analyst
Log the examined hosts and findings. If a side-load was confirmed, recommend a detection rule for directory-proximity module loads from non-system paths.
```
→ end
Run it
Take this hunt into your environment.
Open it in Huntbase to run every step against your own connections, with Scout weighing the evidence and your analysts in command. Or take the open hunt.md file anywhere that reads the format.
Machine-drafted by huntbase-hunt-generation using hb_google/gemini-3-flash-preview, gated by dry-run, lint, then reviewed by a person.