Skip to content

Elastic Defend Setup

BlackSnufkin edited this page May 3, 2026 · 1 revision

Elastic Defend Setup

Full walkthrough for kind: elastic profiles. Three pieces, all operator-managed:

  1. An Elastic stack (Elasticsearch + Kibana + Fleet) β€” LitterBox does NOT deploy or manage one
  2. An EDR Windows VM with Elastic Defend enrolled
  3. A LitterBox profile YAML pointing at both

1. Stand up an Elastic stack

The fastest path is the elastic-container-project, which gives you Elasticsearch + Kibana + Fleet locally. Follow their README to spin it up.

Once Kibana is reachable:

  1. Enable the Elastic Defend integration on a Fleet policy.

    • Kibana β†’ Fleet β†’ Agent policies β†’ create one (or use the default).
    • Add the Elastic Defend integration; configure for endpoint protection.
  2. Enroll your EDR Windows VM into that policy.

    • Kibana β†’ Fleet β†’ Agents β†’ Add agent β†’ copy the install command, run on the VM.
    • The Elastic Agent installs Defend automatically per the policy.
  3. (Recommended) Enable Detection-Engine rules.

    • Kibana β†’ Security β†’ Manage β†’ Rules β†’ enable the Elastic prebuilt rules.
    • The default rule pack covers most common malware behaviors.
  4. Create an API key with read access to the alert indices.

    • Kibana β†’ Stack Management β†’ API keys β†’ Create API key.
    • Required indices: .alerts-security.alerts-*, .internal.alerts-security.alerts-*, .ds-logs-endpoint.alerts-*.
    • Copy the encoded value β€” you'll paste it into the profile YAML.

2. Deploy Whiskers on the EDR VM

See Whiskers Agent for the full guide. Quick version:

# on the EDR VM
mkdir C:\Tools -Force
# copy Whiskers.exe to C:\Tools\

New-NetFirewallRule -DisplayName "Whiskers Agent" -Direction Inbound `
    -Protocol TCP -LocalPort 8080 -Action Allow

# Auto-start on logon (recommended)
C:\Tools\Whiskers.exe --install

Add Whiskers as a Trusted Application in Defend's policy. Kibana β†’ Security β†’ Manage β†’ Trusted Applications β†’ add the Whiskers process path. Without this Defend will start blocking the spawned payloads BEFORE Whiskers even returns β€” you'll see agent_unreachable errors.


3. Configure the LitterBox profile

Copy the example and fill in real values:

cp Config/edr_profiles/elastic.yml.example Config/edr_profiles/elastic.yml

The real elastic.yml is gitignored. Edit it:

name: "elastic"
display_name: "Elastic Defend"
kind: "elastic"                # default β€” can be omitted for back-compat

agent_url: "http://<edr-vm-ip>:8080"
elastic_url: "https://<elastic-stack-ip>:9200"
elastic_apikey: "<base64-encoded-key-from-step-1>"
elastic_verify_tls: false      # self-signed cert from elastic-container-project

wait_seconds_for_alerts: 90    # max poll window for successful execs
av_block_wait_seconds: 60      # max poll window for AV-block events
exec_timeout_seconds: 60       # how long to let the payload run

hostname is not configured β€” the agent self-reports it via /api/info, so moving the agent to a different VM is transparent.

Restart LitterBox after editing the YAML. The upload page gains a button per registered profile.


Smoke-test the wire

From LitterBox host:

# Are profiles loaded?
python GrumpyCats/grumpycat.py edr-profiles

# Live agent + Elastic reachability probe (cached server-side)
python GrumpyCats/grumpycat.py edr-status

If both look healthy, dispatch a benign sample:

# Upload first
python GrumpyCats/grumpycat.py upload calc.exe
# Then dispatch (replace with the returned MD5)
python GrumpyCats/grumpycat.py edr-run <md5> --profile elastic --wait

The dashboard at / will show the EDR profile reachable, and /whiskers will show full status (agent + Elastic cluster reachability, lock state, hostname).


Default Elastic index pattern

.ds-logs-endpoint.alerts-default-*,.internal.alerts-security.alerts-default-*

Covers Elastic 9.x stacks deployed via elastic-container-project. The first index holds Elastic Defend endpoint alerts (real-time host detections from the agent); the second holds Detection Engine signals (rules raised against ingested events). The orchestrator's _normalize() reads from BOTH schemas:

Schema Rule name field Severity field
.ds-logs-endpoint.alerts-* (Defend endpoint) rule.name numeric event.severity
.internal.alerts-security.alerts-* (Detection Engine) kibana.alert.rule.name string severity

Older clusters or different deployments can override per-profile via elastic_index_pattern.


Per-payload alert correlation

The query is scoped by:

  • host.name (case-insensitive, since Whiskers reports DESKTOP-X and ECS often stores desktop-x)
  • @timestamp >= run_start AND @timestamp <= run_end
  • AND at least one of the following matches the payload filename:
    • file.name (term)
    • process.name (term)
    • file.path (wildcard *<filename>)
    • process.executable (wildcard)
    • process.command_line (wildcard) β€” picks up rundll32-launched DLLs where the DLL only appears in the parent's command line
    • process.args (wildcard)

The MD5-prefixed dropper filename is unique enough across uploads that concurrent dispatches from different operators don't taint each other's results.


Troubleshooting

agent_unreachable on every dispatch Whiskers can't be reached. From LitterBox: curl http://<vm>:8080/api/info. If that fails: firewall rule, wrong IP, agent crashed, or Defend killed the agent (add Whiskers to Trusted Applications).

busy on every dispatch Lock is held β€” typically a previous orchestrator crashed mid-run. curl -X POST http://<vm>:8080/api/lock/release to clear. The lock also auto-expires after 30 min.

Payload spawns but Phase 2 finds zero alerts

  • Defend isn't enrolled correctly β€” check Kibana β†’ Fleet β†’ Agents.
  • Detection rules aren't enabled β€” Kibana β†’ Security β†’ Manage β†’ Rules.
  • Index pattern wrong β€” confirm via python GrumpyCats/grumpycat.py edr-status.
  • API key lacks read access to the alert indices β€” recreate with the right index permissions.
  • Wait window too short β€” bump wait_seconds_for_alerts (default 90s; rule cycles run every 60s, so 90s catches the first scheduled run with margin).

Phase 2 ends with partial Phase 1 succeeded but the Elastic query failed. Look at the sub_status field β€” elastic_unreachable (transport) or elastic_error (HTTP error from the cluster). Often: stale API key, certificate mismatch, or wrong elastic_url.

status: blocked_by_av with no alerts Defend blocked the spawn before Whiskers could exec. Whiskers reports status:"virus" (Windows errno 225/995/1234); the orchestrator surfaces this as summary.blocked_by_av: true. The Phase 2 poll still queries Elastic for the prevention alert; if it lands, you'll see it in the alerts list.


See also

πŸ“Œ LitterBox Β· self-hosted payload analysis sandbox

Release


πŸš€ Getting Started

πŸ“Š Pipelines & Pages

πŸ”¬ Scanners Β· 4 modules

πŸ›°οΈ EDR Integration
πŸ”Œ API & Clients
βš™οΈ Configuration & Dev

Releases Β· CHANGELOG Β· Issues Β· README

Clone this wiki locally