<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Integrations & Tools - Elastic Security Labs]]></title>
    <description><![CDATA[Trusted security news & research from the team at Elastic.]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Integrations & Tools - Elastic Security Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte2c6b841aff36df4/6a88d9784acc96e3f324863d/security-labs-thumbnail.png</url>
      <link>https://www.elastic.co/security-labs/blog/category/integrations-tools</link>
    </image>
    <link>https://www.elastic.co/security-labs/blog/category/integrations-tools</link>
    <atom:link href="https://www.elastic.co/security-labs/rss/category/integrations-tools.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[en]]></language>
    <lastBuildDate>Mon, 14 Sep 2026 20:18:40 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Stop rewriting detection rules by hand: automatic Sentinel-to-Elastic migration is here]]></title>
    <description><![CDATA[Elastic's first automatic migration from a modern SIEM. Translate your Sentinel detection rules into Elastic Security without rebuilding them.]]></description>
    <content:encoded><![CDATA[<p>Elastic automatically translates your Microsoft Sentinel detection rules into Elastic Security. Export your Scheduled and Near Real Time (NRT) analytics rules from Sentinel, upload them, and Elastic picks up the mapping and translation from there using an LLM you choose. Watchlists and severity mappings carry over. This is the first automatic migration path off a modern SIEM, available now in Tech Preview in 9.5, and it works across multiple cloud providers and regions so you can deploy closer to where your data lives.</p>
<h2 id="whichmicrosoftsentinelruletypescanbemigratedautomatically">Which Microsoft Sentinel rule types can be migrated automatically?</h2>
<p>Automatic Migration focuses on the rules that carry your detection logic. In 9.5, it translates Scheduled and Near Real Time (NRT) analytics rules from Microsoft Sentinel, exported from your Sentinel workspace, and handles the translation for you.</p>
<p>It uses the same <a href="https://www.elastic.co/blog/automatic-migration-ai-rule-translation">mapping and translation</a> as our existing rule migrations, now extended to Microsoft Sentinel.  The following are supported:</p>
<ul>
<li>Integration identification with just rule export  </li>
<li>Support for the following rule types:  </li>
<li>Near-real-time (NRT) detection analytics rules  </li>
<li>Scheduled Analytic Rules  </li>
<li>Support for Watchlists to ES|QL Lookups  </li>
<li>Severity Mapping</li>
</ul>
<h2 id="howtomigratemicrosoftsentineldetectionrulestoelastic"><strong>How to migrate Microsoft Sentinel detection rules to Elastic</strong></h2>
<p>The migration runs in a few steps, from exporting your rules in Sentinel to reviewing the translated versions in Elastic. Once you've decided which rules and data to migrate, follow these steps:</p>
<ol>
<li>On the Security Launchpad, open Manage Automatic Migrations, select your AI provider, and expand Migrate your existing SIEM rules to Elastic.</li>
</ol>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7f836ebffc586e5b/6a7d8414ea068db7d3f07264/image2.png" alt="" /></p>
<ol>
<li>Select the drop-down on the top right for Microsoft Sentinel. Let Elastic guide you through exporting your rules from Sentinel and uploading them into Elastic Security. Elastic handles the finer details by scanning for watchlists and then prompts you to upload them when found.</li>
</ol>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltaa35d9817a6e656c/6a7d841773d9bdd5ae29ac4c/image3.png" alt="" /></p>
<ol>
<li>Once the rules are uploaded, you can view their status. </li>
</ol>
<ul>
<li>Installed: Already added to Elastic SIEM. Click View to manage and enable it.  </li>
<li>Translated: Ready to install. This rule was mapped to an Elastic-authored rule, or translated by <a href="https://www.elastic.co/docs/explore-analyze/ai-features/automatic-import">Automatic Import</a>. Click Install to install it.  </li>
<li>Partially translated: Part of the query could not be translated. You may need to specify an index pattern for the rule query, upload missing files, or fix broken rule syntax.  </li>
<li>Not translated: None of the original query could be translated.  </li>
<li>Failed: Translation failed. Refer to the error for details.</li>
</ul>
<p>For more information, refer to the <a href="https://www.elastic.co/docs/solutions/security/get-started/automatic-migration">technical documentation</a>.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1dda7a8cf9ee9c60/6a7d841a227b1c8c90595854/image1.png" alt="Translation summary showing 34 of 35 Microsoft Sentinel detection rules successfully translated to Elastic Security in 15 minutes, with status breakdown by translated, partially translated, not translated and failed" title="Translation summary showing 34 of 35 Microsoft Sentinel detection rules successfully translated to Elastic Security in 15 minutes, with status breakdown by translated, partially translated, not translated and failed" /></p>
<ol>
<li>After clicking View Rules, you will have the ability to edit and install rules. </li>
</ol>
<h2 id="shouldyoumigraterulesfirstordatafirst">Should you migrate rules first or data first?</h2>
<p>One of the first decisions in a migration is sequencing: data or rules first. Elastic supports both paths, so you can start wherever makes sense for your team. </p>
<p>| Path | When to use | What happens |
| :---- | :---- | :---- |
| Rules first | You do not know exactly which data sources to prioritise before moving any logs. | Translate your Sentinel rules first. Elastic identifies which integrations those rules need, so you can plan data onboarding around what your detections actually require. |
| Data first | Your log sources are already being onboarded, or you want detections to work the moment they're installed. Onboarding data beforehand improves the translation quality.  | Onboard your log sources into Elastic, then migrate your Sentinel rules to match. Rules can be installed and enabled immediately against data that's already flowing.  |
| Custom data | You have proprietary or non-standard log sources that don't map to a prebuilt Elastic integration. | Use <a href="https://www.elastic.co/blog/elasticsearch-custom-integrations-automatic-import">Automatic Import</a> to ingest custom data sources in minutes, then migrate or write rules against them. |</p>
<p>By identifying exactly which integrations are needed before moving a single log, teams can build a precise, risk-aware roadmap for their migration project. This transparency eliminates the guesswork and helps ensure that critical visibility gaps are addressed long before you fully decommission your environment.</p>
<h2 id="whathappensafteryoursentinelrulesarerunninginelastic">What happens after your Sentinel rules are running in Elastic</h2>
<p>Once your rules are running in Elastic, <a href="https://www.elastic.co/docs/explore-analyze/workflows">Workflows</a> lets you build automation around them. The moment a rule fires, a workflow can kick off multi-step remediation, enrichment, and notification automatically. And building these automations in <a href="https://www.elastic.co/docs/solutions/security/ai/agent-builder/agent-builder">Agent Builder</a> lowers the barrier, so you can create a workflow in natural language.</p>
<h2 id="howelasticaifitsintoasentineltoelasticmigration">How Elastic AI fits into a Sentinel-to-Elastic migration</h2>
<p>Elastic Security brings generative AI into the SOC with <a href="https://www.elastic.co/docs/solutions/search/rag">retrieval augmented generation (RAG)</a> and open agentic frameworks. Automatic Migration joins the lineup of Elastic Security’s AI features, helping SOC teams strengthen defenses across the IT environment:</p>
<ul>
<li><a href="https://www.elastic.co/docs/solutions/security/get-started/automatic-migration">Automatic Migration for Detection Rules</a> complements Elastic’s deep library of prebuilt rules to broaden detection use case coverage.  </li>
<li><a href="https://www.elastic.co/blog/elasticsearch-custom-integrations-automatic-import">Automatic Import</a> extends visibility <em>and powers detection rules</em> by onboarding custom data sources in minutes.  </li>
<li><a href="https://www.elastic.co/security-labs/skills-elastic-security-9-4">Agent Skills</a> assist in the response process and less time context switching.</li>
</ul>
<p>Elastic’s SIEM and XDR solution helps analysts detect earlier and respond faster.</p>
<h2 id="tryautomaticdetectionrulemigration">Try automatic detection rule migration</h2>
<p>Migrating a SIEM has always meant rebuilding your detection rules by hand, and that cost is what keeps teams on a platform long after they've decided to leave. Automatic Migration simplifies that process, providing mapping to existing Elastic rules and helping to translate the rest. Your watchlists and severity levels carry over as well, and you move on your own terms, with your data and your tooling under your control. For further details check out our <a href="https://www.elastic.co/docs/solutions/security/get-started/automatic-migration">documentation</a>. </p>
<p><a href="https://www.elastic.co/cloud/cloud-trial-overview">Try it free</a>, or <a href="https://www.elastic.co/splunk-interest?elektra=organic&amp;storm=CLP&amp;rogue=splunkobs-gic">get in touch</a>. Have feedback? Tell us what you think in the <a href="https://elasticstack.slack.com/">Elastic Community Slack channel</a> or on the <a href="https://discuss.elastic.co/c/security/83">Elastic Security forum</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/sentinel-detection-rules-migration</link>
    <guid isPermaLink="false">sentinel-detection-rules-migration</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Charles Davison]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6da0fe5119268e0b/6a7d841d3cab1ce59f0e1a46/image4.jpg" length="0" type="image/jpeg"/>
    <pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[From API key to live threat detections in minutes: how Elastic Security ingests Google Threat Intelligence]]></title>
    <description><![CDATA[Find out how Elastic Security ingests Google Threat Intelligence for continuous detection and uses AI-driven workflows to enrich alerts in real time, from API key to live detections in minutes.]]></description>
    <content:encoded><![CDATA[<p>Elastic Security natively ingests Google Threat Intelligence: known-malicious IPs, domains, URLs, and file hashes matched against your telemetry the moment they appear, each carrying a verdict and a 0–100 threat score. The setup consists of an API key and two data streams, with no extra infrastructure. When an indicator is ambiguous, workflows built on Agent Builder query VirusTotal in real time, enrich the alert, correlate with your telemetry, and summarize findings in real time. </p>
<h2 id="howthreatintelligenceworksinelasticsecurity">How threat intelligence works in Elastic Security</h2>
<p>In modern security operations, threat intelligence must work across detection, investigation, and response, not sit in a reference table.</p>
<p>Elastic Security supports this in two ways. Ingested intelligence via <a href="https://www.elastic.co/docs/reference/integrations/threat-intelligence-intro">integrations</a> drives continuous detection and historical hunting. Agentic workflows, built on Elastic Workflows and Agent Builder, provide on-demand enrichment and investigative reasoning during an active investigation. This post focuses on how Elastic's Google Threat Intelligence (GTI) integration powers ingestion-based detection and hunting, and how it fits into a broader, more dynamic SOC model where AI-driven workflows use that intelligence at alert time.</p>
<h2 id="whatgooglethreatintelligenceprovides">What Google Threat Intelligence provides</h2>
<p>The Google Threat Intelligence integration brings curated threat intelligence directly into Elastic Security, making it actionable across detection and investigation. GTI combines intelligence from Google's global security visibility with VirusTotal data to deliver enriched context on indicators of compromise, with coverage across malware, ransomware, phishing, infostealers, malicious infrastructure, threat actors, and other adversary activity.</p>
<p>Each indicator is returned with: a verdict (Malicious, Suspicious, or Undetected), a severity, and a composite threat score from 0–100. Because that score is derived from multiple signals, security teams can prioritize indicators based on confidence rather than their presence alone.</p>
<h2 id="howthegooglethreatintelligenceintegrationworksinelasticsecurity">How the Google Threat Intelligence integration works in Elastic Security</h2>
<p>Setup takes only a few minutes. You provide your GTI API key in the Elastic integration, and ingestion begins on a scheduled polling interval, with no additional infrastructure or collectors required. The integration ingests two primary data streams.</p>
<p>| Purpose | Threat List | IOC Stream |
|--------|-------------|------------|
| Purpose | High-confidence detection | Threat hunting + early visibility |
| Volume | Curated, lower volume | Broader, higher volume |
| Best for | Precision-critical alerting | Emerging and exploratory activity |</p>
<p>As data is ingested, indicators are standardized using the Elastic Common Schema (ECS), along with GTI context, such as verdict, severity, score, malware families, threat actor associations, and campaign metadata (where available). This enables GTI to be searched and correlated consistently alongside other ECS-compliant intelligence sources (including TAXII feeds), custom intelligence, and the broader security telemetry already present in Elastic Security. Elastic also manages indicator lifecycle automatically, including expiration and revocation, which reduces matches against stale intelligence. Once ingested, GTI indicators become part of the same searchable dataset as logs, endpoint, and cloud telemetry, enabling unified correlation across the environment.</p>
<h2 id="usinggooglethreatintelligenceforindicatormatchdetections">Using Google Threat Intelligence for indicator match detections</h2>
<p>Elastic's <a href="https://www.elastic.co/docs/solutions/security/detect-and-alert/indicator-match">indicator match rules</a> use GTI data to detect when known malicious IPs, domains, URLs, or file hashes appear in security telemetry, continuously correlating intelligence against observed activity and surfacing matches for investigation. Because GTI provides structured fields such as score, verdict, and severity, teams can tune detections by confidence: high-confidence indicators can trigger immediate escalation, while lower-confidence indicators can be routed for review or further validation.</p>
<h2 id="threathuntingwithgtiindicatorsinelasticsecurity">Threat hunting with GTI indicators in Elastic Security</h2>
<p>With GTI metadata, analysts can pivot from a single IOC to all associated infrastructure and search historical telemetry; not just check if an indicator appeared, but understand what campaign it belongs to.</p>
<p>GTI enriches indicators with metadata such as threat actor associations and malware family context, allowing analysts to move beyond single-IOC searches. Hunters can pivot from an adversary or campaign to all associated indicators (IPs, domains, and file hashes) and search across historical telemetry using ES|QL. This makes it straightforward to determine whether known malicious infrastructure has ever interacted with the environment.</p>
<h2 id="monitoringthreatintelligenceactivitywithgtidashboards">Monitoring threat intelligence activity with GTI dashboards</h2>
<p>The integration includes prebuilt dashboards that provide visibility into threat intelligence activity and the detections GTI drives. Using saved searches and aggregated metrics, these dashboards summarize observed threats across malware families, campaigns, threat actors, toolkits, and vulnerabilities, helping SOC teams understand which threat types are most active in their environment and how intelligence is being operationalized.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5e9ea4f4c8281953/6a7d7f838fc2d071393eb86d/image1.png" alt="Elastic Security’s Google Threat Intelligence Adversary Intelligence dashboard" title="Elastic Security’s Google Threat Intelligence Adversary Intelligence dashboard" /></p>
<h3 id="googlethreatintelligencefeedcategoriesandcoverage">Google Threat Intelligence feed categories and coverage</h3>
<p>GTI includes 14 categorized feed categories, so organizations can tailor coverage to their needs and subscription level. Supported categories include:</p>
<ul>
<li>Cryptominers</li>
<li>Trending threats</li>
<li>Initial access and delivery vectors</li>
<li>Infostealers</li>
<li>IoT threats</li>
<li>Linux malware</li>
<li>Malicious infrastructure</li>
<li>General malware</li>
<li>Mobile threats</li>
<li>macOS threats</li>
<li>Phishing</li>
<li>Ransomware</li>
<li>Threat actors</li>
<li>Vulnerability exploitation and weaponization</li>
</ul>
<p>Availability depends on your Google Threat Intelligence subscription tier, and additional feeds can be enabled without changes to the Elastic configuration.</p>
<h2 id="agenticenrichmentandrealtimetriagewithelasticworkflows">Agentic enrichment and real-time triage with Elastic Workflows</h2>
<p>For ambiguous or emerging indicators not yet in an indexed feed, Elastic Security supports AI-driven investigation through Agent Builder and Elastic Workflows, which complement intelligence ingestion by enabling real-time enrichment and reasoning during an investigation.</p>
<p>With workflows, an analyst is no longer limited to the intelligence already in the index. During alert triage, a workflow can query external intelligence and reputation services such as VirusTotal in real time, enrich an alert with fresh context about the IPs, domains, or file hashes involved, correlate that live intelligence against Elastic telemetry, and summarize the findings into a structured investigation context that the analyst can act on. Agent Builder extends this further: teams can compose reusable, task-specific capabilities, such as agent skills for alert triage, enrichment, or case handling, so the assistant executes multi-step investigative tasks with the consistency of traditional automation, through a natural-language interface.</p>
<p>![Elastic Workflows editor showing the "Send Hash to VirusTotal" workflow](https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6a78dda4577bd409/6a7d7f864c4bfb416dcca811/image3.png "Elastic Workflows editor showing the \"Send Hash to VirusTotal\" workflow")</p>
<p>This introduces a complementary model. Ingested intelligence (GTI, TAXII, and custom feeds) provides continuous detection and historical hunting against indicators you already hold. Agentic workflows provide on-demand enrichment and investigative reasoning at alert time, reaching out to live sources and assembling context on the fly. Together, they enable teams to detect known threats at scale and provide context to investigations.</p>
<h2 id="gettingstartedwithgooglethreatintelligenceinelasticsecurity">Getting started with Google Threat Intelligence in Elastic Security</h2>
<p>To use the <a href="https://www.elastic.co/docs/reference/integrations/ti_google_threat_intelligence">Google Threat Intelligence integration</a> in Elastic Security, you need an active GTI license and API key.</p>
<ol>
<li><strong>Install:</strong> open Integrations catalog in Kibana → search "Google Threat Intelligence" → add integration → enter your API key</li>
<li><strong>Configure the data streams:</strong> enable Threat List (high-confidence detections) and IOC Stream (hunting coverage) → set polling frequency to match API limits and operational needs</li>
<li><strong>Tune:</strong> prebuilt indicator match rules activate automatically; if alert volume is high, start by filtering on confidence threshold</li>
</ol>
<p>All indicators are stored in Elasticsearch and accessible through the GTI threat intelligence data view, enabling search, correlation, and custom detection logic. Full configuration details and troubleshooting guidance are available in the official documentation.</p>
<h2 id="tyingitalltogether">Tying it all together</h2>
<p>Threat intelligence only matters if a team can act on it. By bringing Google Threat Intelligence into Elastic Security, SOC teams get ingestion-based detection running continuously across their telemetry and agent-driven investigation reasoning over that intelligence in real time. The combination lets threat intelligence operate continuously and contextually, helping analysts move from indicators to confident decisions faster.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/elastic-security-google-threat-intelligence</link>
    <guid isPermaLink="false">elastic-security-google-threat-intelligence</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Jamie Hynds,Mia LaVada]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6b515b033b0962c4/6a7d7f89bd21985f46755287/image2.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 02 Jun 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Monitoring Claude Code/Cowork at scale with OTel in Elastic]]></title>
    <description><![CDATA[How Elastic's InfoSec team built a monitoring pipeline for Claude Code and Claude Cowork using their native OTel export capabilities and Elastic's OTel ingestion infrastructure.]]></description>
    <content:encoded><![CDATA[<p>As AI coding assistants become standard tools in engineering workflows, security teams face a new challenge: how do you maintain visibility into what an AI agent is doing (and why) across your organization? When those agents can execute shell commands, read files, call APIs, and interact with internal systems via MCP connectors, you need real-time observability to support threat detection, incident response, and compliance.</p>
<p>This post walks through how Elastic's InfoSec team built a monitoring pipeline for <a href="https://code.claude.com/">Claude Code</a> and <a href="https://claude.com/docs/cowork">Claude Cowork</a> using their native <a href="https://opentelemetry.io/">OpenTelemetry (OTel)</a> export capabilities and Elastic's own OTel ingestion infrastructure. We cover the telemetry schema, the gateway deployment, custom Elasticsearch mappings and ingest pipelines, managed configuration delivery, and the security use cases enabled by this data.</p>
<h2 id="whyelasticsinfosecteammonitorsaiagents">Why Elastic's InfoSec team monitors AI agents</h2>
<p>At Elastic, we practice what we call "Customer Zero." The InfoSec team is the first and most demanding user of Elastic's products, always running the newest versions in production. Our goal is to use our own products to improve our security posture whenever we can.</p>
<p>Claude Code and Cowork are now in active use across Elastic's engineering organization. Claude Code runs locally on developer machines as a CLI-based AI coding assistant. Cowork is part of the Claude Desktop app and also runs locally. It can read files, execute code in a sandbox, search the web, and interact with connected services like Slack, GitHub, Jira, and Google Calendar through MCP connectors. Both tools support connecting to internal systems, which means they operate in a trust boundary that security teams need to monitor.</p>
<h2 id="whatclaudecodeandcoworkexportviaopentelemetry">What Claude Code and Cowork export via OpenTelemetry</h2>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt36c8796faec1efd7/6a7d7e0a3ce8e24898cf25f0/image2.png" alt="" /></p>
<p>Both products export telemetry through standard OpenTelemetry protocols, emitting the same five event types:</p>
<ul>
<li><code>api_request</code> — model, cost, token counts, latency  </li>
<li><code>tool_result</code> — tool name, MCP server and tool name, success/failure, duration  </li>
<li><code>tool_decision</code> — auto-approved vs user-approved  </li>
<li><code>user_prompt</code> — what the user asked the agent to do  </li>
<li><code>api_error</code> — error message, status code</li>
</ul>
<p>Every event includes user identity (<code>user.email</code>, <code>organization.id</code>), session context (<code>session.id</code>, <code>prompt.id</code>, <code>event.sequence</code>), and cost/token fields on API request events. Claude Code telemetry is opt-in and redacts prompts and tool arguments by default; enable them with <code>OTEL_LOG_USER_PROMPTS=1</code> and <code>OTEL_LOG_TOOL_DETAILS=1</code>. Cowork is configured centrally in the Anthropic admin portal and includes full details automatically.</p>
<p>For the full telemetry schema, see the <a href="https://code.claude.com/docs/en/monitoring-usage">Claude Code Monitoring documentation</a> and the <a href="https://claude.com/docs/cowork/monitoring">Claude Cowork Monitoring documentation</a>.</p>
<h2 id="architecturegettingthedatatoelasticsearch">Architecture: Getting the data to Elasticsearch</h2>
<p>There are two ways to get Claude Code and Cowork OTel data into Elasticsearch. We deployed the self-managed gateway approach first, but Elastic Cloud users have a simpler option.</p>
<h3 id="option1edototelgatewayselfmanaged">Option 1: EDOT OTel Gateway (self-managed)</h3>
<p>This is the approach we used internally. Since Elastic's InfoSec team runs self-managed ECK (Elastic Cloud on Kubernetes) clusters, we deployed an <a href="https://www.elastic.co/docs/reference/edot-collector">Elastic Distribution of the OpenTelemetry Collector (EDOT)</a> as a gateway. Both Claude Code and Cowork run locally on user machines and send OTLP/HTTP to the gateway, which authenticates the request and writes to Elasticsearch.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt96dd4e11dc6411e2/6a7d7e0de3a2195d4099c693/image4.png" alt="" /></p>
<p>We used the <a href="https://github.com/open-telemetry/opentelemetry-helm-charts">opentelemetry-collector Helm chart</a> with the EDOT collector image (<code>docker.elastic.co/elastic-agent/elastic-otel-collector</code>). The EDOT image provides native Elastic data stream routing, which is important for getting logs into the right data streams without extra configuration.</p>
<p>The gateway runs in deployment mode and uses bearer token authentication via the <a href="https://www.elastic.co/docs/reference/edot-collector/config/authentication-methods"><code>bearertokenauth</code> extension</a>.</p>
<p>Here is the core collector configuration:</p>
<pre><code>config:
  extensions:
    bearertokenauth:
      scheme: "Bearer"
      token: "${env:OTEL_GATEWAY_TOKEN}"
  receivers:
    otlp:
      protocols:
        http:
          endpoint: "0.0.0.0:4318"
          auth:
            authenticator: bearertokenauth
  processors:
    transform/route:
      log_statements:
        - context: log
          conditions:
            - resource.attributes["service.name"] == "claude-code"
          statements:
            - set(resource.attributes["data_stream.dataset"], "claude_code")
        - context: log
          conditions:
            - resource.attributes["service.name"] == "cowork"
          statements:
            - set(resource.attributes["data_stream.dataset"], "claude_cowork")
  exporters:
    elasticsearch:
      endpoints: ["https://your-elasticsearch:9200"]
      user: "${env:ES_USERNAME}"
      password: "${env:ES_PASSWORD}"
  service:
    extensions: [bearertokenauth]
    pipelines:
      logs:
        receivers: [otlp]
        processors: [transform/route]
        exporters: [elasticsearch]
</code></pre>
<h3 id="option2elasticcloudmanagedotlpendpointnogatewayneeded">Option 2: Elastic Cloud Managed OTLP Endpoint (no gateway needed)</h3>
<p>If you are running Elastic Cloud (Serverless or Hosted), you can skip the gateway entirely. Elastic's <a href="https://www.elastic.co/docs/reference/opentelemetry/motlp">Managed OTLP (mOTLP) endpoint</a> provides a resilient, auto-scaling ingestion layer that accepts OTLP data directly — no collector infrastructure to deploy or maintain.</p>
<p>To use it, point Claude Code's OTLP exporter directly at your Elastic Cloud mOTLP endpoint:</p>
<pre><code>export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_LOGS_EXPORTER=otlp
export OTEL_METRICS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_ENDPOINT="https://&lt;your-motlp-endpoint&gt;"
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=ApiKey &lt;your-api-key&gt;"
export OTEL_RESOURCE_ATTRIBUTES="data_stream.dataset=claude_code"
</code></pre>
<p>The <code>data_stream.dataset</code> resource attribute is important here; it controls which data stream receives the logs. Without it, data lands in a generic OTel data stream where your custom index templates and ingest pipelines will not apply. Set it to <code>claude_code</code> or <code>claude_cowork</code> so the data routes to the dedicated <code>logs-claude_code.otel-*</code> or <code>logs-claude_cowork.otel-*</code> streams with the correct field mappings.</p>
<p>With mOTLP, you get native OTLP ingestion with automatic data stream routing, a built-in failure store to protect data during indexing issues, and no APM Server requirement.</p>
<p>The managed endpoint supports all the same custom index templates and ingest pipelines described below, you just don't need to operate the gateway.</p>
<p>For full setup details, see the <a href="https://www.elastic.co/docs/reference/opentelemetry/motlp">Elastic Cloud Managed OTLP documentation</a>. Note that it is not currently possible to control index permissions for mOTLP.</p>
<h2 id="customelasticsearchmappingsandingestpipelines">Custom Elasticsearch mappings and ingest pipelines</h2>
<p>By default, OTel attributes are indexed as keywords in Elasticsearch. That works for filtering and grouping, but it breaks numeric aggregations. You cannot SUM or AVG a keyword field. We created custom mappings to fix the field types and an ingest pipeline to parse JSON string fields into structured objects.</p>
<h3 id="componenttemplate">Component template</h3>
<p>The component template overrides the default keyword mappings for numeric and boolean fields, and adds <code>flattened</code> type mappings for the JSON-encoded tool parameters:</p>
<pre><code>PUT _component_template/logs-claude_code.otel@custom
{
  "template": {
    "mappings": {
      "properties": {
        "cost_usd":                  { "type": "float" },
        "duration_ms":               { "type": "long" },
        "input_tokens":              { "type": "long" },
        "output_tokens":             { "type": "long" },
        "cache_creation_tokens":     { "type": "long" },
        "cache_read_tokens":         { "type": "long" },
        "prompt_length":             { "type": "long" },
        "tool_result_size_bytes":    { "type": "long" },
        "success":                   { "type": "boolean" },
        "tool_parameters_flattened": { "type": "flattened" },
        "tool_input_flattened":      { "type": "flattened" }
      }
    }
  }
}
</code></pre>
<p>The <code>flattened</code> type is important here. <code>tool_parameters</code> and <code>tool_input</code> arrive as JSON strings containing nested keys like <code>mcp_server_name</code>, <code>mcp_tool_name</code>, <code>bash_command</code>, or <code>command</code>. By parsing them into <code>flattened</code> fields, you can query individual keys without creating an unbounded number of mapped fields.</p>
<p>A future enhancement will be to extract high-value fields from these JSON payloads into dedicated mapped fields — things like MCP server names, tool names, and bash commands — to drive richer analytics, aggregations, and detection rules directly on those values.</p>
<h3 id="indextemplate">Index template</h3>
<p>The index template composes in all the standard OTel component templates plus our custom one. It matches both <code>logs-claude_code.otel-*</code> and <code>logs-claude_cowork.otel-*</code> so both data streams share the same field mappings:</p>
<pre><code>PUT _index_template/logs-claude_code.otel
{
  "index_patterns": [
    "logs-claude_code.otel-*",
    "logs-claude_cowork.otel-*"
  ],
  "composed_of": [
    "logs@mappings",
    "logs@settings",
    "otel@mappings",
    "otel@settings",
    "logs-otel@mappings",
    "semconv-resource-to-ecs@mappings",
    "logs@custom",
    "logs-otel@custom",
    "logs-claude_code.otel@custom",
    "ecs@mappings"
  ],
  "priority": 150,
  "data_stream": {},
  "allow_auto_create": true,
  "ignore_missing_component_templates": [
    "logs@custom",
    "logs-otel@custom"
  ]
}
</code></pre>
<h3 id="ingestpipeline">Ingest pipeline</h3>
<p>The ingest pipeline parses <code>tool_parameters</code> and <code>tool_input</code> from JSON strings into objects, writing to separate <code>*_flattened</code> target fields to avoid conflicts with the original keyword-mapped attributes:</p>
<pre><code>PUT _ingest/pipeline/logs-claude_code.otel@custom
{
  "description": "Parse JSON string fields in Claude Code/Cowork OTel telemetry",
  "processors": [
    {
      "json": {
        "field": "attributes.tool_parameters",
        "target_field": "tool_parameters_flattened",
        "if": "ctx.attributes?.tool_parameters != null &amp;&amp; ctx.attributes.tool_parameters.startsWith('{')",
        "ignore_failure": true
      }
    },
    {
      "json": {
        "field": "attributes.tool_input",
        "target_field": "tool_input_flattened",
        "if": "ctx.attributes?.tool_input != null &amp;&amp; ctx.attributes.tool_input.startsWith('{')",
        "ignore_failure": true
      }
    }
  ]
}
</code></pre>
<p>After creating all three resources, new data flowing into the <code>logs-claude_code.otel-*</code> and <code>logs-claude_cowork.otel-*</code> data streams will have correct numeric field types and searchable structured tool parameters.</p>
<h2 id="configuringtelemetryexport">Configuring telemetry export</h2>
<p>Claude Code and Cowork are configured differently. Claude Code uses standard OpenTelemetry environment variables. Cowork OTel export is configured centrally by administrators in the Anthropic admin portal.</p>
<p>Claude Code supports <a href="https://code.claude.com/docs/en/settings#settings-files">managed settings</a> that are deployed by IT and cannot be overridden by users. The configuration is a JSON file containing an <code>env</code> block:</p>
<pre><code>{
  "env": {
    "CLAUDE_CODE_ENABLE_TELEMETRY": "1",
    "OTEL_METRICS_EXPORTER": "otlp",
    "OTEL_LOGS_EXPORTER": "otlp",
    "OTEL_LOG_TOOL_DETAILS": "1",
    "OTEL_LOG_USER_PROMPTS": "1",
    "OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
    "OTEL_EXPORTER_OTLP_ENDPOINT": "https://your-otel-gateway:443",
    "OTEL_EXPORTER_OTLP_HEADERS": "Authorization=Bearer your-token"
  }
}
</code></pre>
<p>This managed settings file can be delivered via MDM (Jamf, Intune), server-managed settings through the Claude.ai Admin Console, or file-based deployment. See the <a href="https://code.claude.com/docs/en/settings#settings-files">Claude Code managed settings documentation</a> for the full list of delivery mechanisms and their security properties.</p>
<p>For local testing, you can put the same configuration in <code>~/.claude/settings.json</code> on your own machine before rolling it out organization-wide.</p>
<h3 id="cowork">Cowork</h3>
<p>Cowork OTel export is configured centrally by administrators in the Anthropic admin portal. Administrators set the OTLP endpoint and authentication headers in the admin console, and Cowork instances automatically pick up the configuration. Prompt content and tool details are included by default without requiring additional flags.</p>
<p>Because Cowork runs in a sandbox, the OTel gateway endpoint must be allowlisted for outbound network access from the sandbox environment. Without this, telemetry export will fail silently.</p>
<h2 id="securityusecases">Security use cases</h2>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc8890c89905f36a3/6a7d7e105588adeefdee4264/image1.png" alt="" /></p>
<p>The combination of event types, identity fields, and tool parameters creates a rich dataset for security operations. Here are the use cases we are building detection and investigation capabilities around.</p>
<p><strong>Tool invocation auditing.</strong> Every tool call is logged with the tool name and input parameters. For MCP tools, this includes the MCP server name and tool name (e.g., <code>slack_send_message</code>, <code>github/search_issues</code>). You can detect unauthorized data access, unusual shell commands, or unexpected MCP server interactions. Use the <code>attributes.tool_name + attributes.tool_parameters</code> fields.</p>
<p><strong>Session reconstruction.</strong> The <code>session.id</code> field combined with <code>event.sequence</code> provides a monotonically increasing counter within each session. You can reconstruct the complete sequence of a Claude session: what the user asked, what tools ran, what data was accessed, and what APIs were called. This is valuable for incident response — if you detect a suspicious tool call, you can pull the full session context.</p>
<p><strong>Permission decision analysis.</strong> The <a href="http://attributes.event.name"><code>attributes.event.name</code></a><code>: tool_decision</code> events provide insight into how each tool use was approved. This lets you detect users auto-approving risky tool categories, or identify unusual permission patterns across the fleet.</p>
<p>| Decision Source | Meaning |
| ----- | ----- |
| <code>config</code> | Auto-allowed by settings or policy |
| <code>hook</code> | Decided by a configured hook script |
| <code>user_temporary</code> | User clicked accept for this invocation |
| <code>user_permanent</code> | User clicked "always allow" for this tool |
| <code>user_abort</code> | User aborted the session |
| <code>user_reject</code> | User explicitly rejected the tool use |</p>
<p><strong>Cost anomaly detection.</strong> The <code>cost_usd</code> field on every <code>api_request</code> event enables per-request, per-session, and per-user cost tracking. You can alert on unusually expensive sessions or identify users with outsized consumption patterns.</p>
<p><strong>Correlating with EDR data.</strong> If you are running <a href="https://www.elastic.co/docs/solutions/security/configure-elastic-defend">Elastic Defend</a> on your endpoints, you can correlate Claude's OTel telemetry with EDR process and file events to understand the full picture. When Claude Code executes a Bash command, the OTel <code>tool_result</code> event tells you what the agent decided to run and why (via the preceding <code>user_prompt</code>). The corresponding Elastic Defend process event tells you exactly what happened on the host — child processes spawned, files written, network connections made. Joining these two data sources by timestamp and host gives you both the intent (from the AI agent telemetry) and the impact (from endpoint telemetry) in a single investigation.</p>
<p><strong>MCP server access monitoring.</strong> As organizations connect AI agents to internal systems through MCP, monitoring which servers are accessed and with what tools becomes critical. The <code>tool_parameters_flattened.mcp_server_name</code> and <code>tool_parameters_flattened.mcp_tool_name</code> fields provide this visibility.</p>
<p>For example, to see tool invocations for Slack, you could query <code>tool_name: "mcp_tool" AND tool_parameters_flattened.mcp_tool_name:slack*</code>.  </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9b9e06f5948a32fb/6a7d7e13c2cc09721a2465e9/image3.png" alt="" /></p>
<h2 id="beyondotelclaudeenterpriseauditlogs">Beyond OTel: Claude enterprise audit logs</h2>
<p>Telemetry from Claude Code and Cowork covers agent activity on endpoints, but it doesn't capture everything. For full visibility, organizations should also collect <a href="https://support.claude.com/en/articles/9970975-access-audit-logs">Claude enterprise audit logs</a> from the Compliance API. This is the only source of activity on the web interface (claude.ai) and of traditional security audit events, such as login activity, permission changes, and organization-level administration. Combining both data sources gives security teams a complete picture across all Claude products.</p>
<h2 id="conclusion">Conclusion</h2>
<p>AI coding assistants and autonomous agents are becoming part of the standard enterprise toolkit. If your security team doesn't have visibility into what these tools are doing, you have a gap. Claude Code and Cowork ship with OpenTelemetry support that provides exactly the kind of telemetry security teams need; identity, session context, tool invocation details, cost data, and permission decisions. Elastic's native OTel ingestion capabilities, whether through the Managed OTLP endpoint on Elastic Cloud or the EDOT Collector in a self-managed environment, make it straightforward to get this data into Elasticsearch, where you can search it, build dashboards, and write detection rules.</p>
<p>If you want to get started, sign up for a <a href="https://cloud.elastic.co/registration">free trial of Elastic Cloud</a> and try the Managed OTLP endpoint, or install the <a href="https://www.elastic.co/docs/reference/edot-collector">EDOT OTel Collector</a> in your existing environment.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://code.claude.com/docs/en/monitoring-usage">Claude Code Monitoring &amp; Telemetry</a>  </li>
<li><a href="https://code.claude.com/docs/en/settings#settings-files">Claude Code Settings — Managed settings</a>  </li>
<li><a href="https://code.claude.com/docs/en/server-managed-settings">Claude Code Server-managed settings</a>  </li>
<li><a href="https://claude.com/docs/cowork/monitoring">Claude Cowork Monitoring</a>  </li>
<li><a href="https://www.elastic.co/docs/reference/opentelemetry/motlp">Elastic Cloud Managed OTLP Endpoint</a>  </li>
<li><a href="https://www.elastic.co/docs/reference/edot-collector">EDOT OTel Collector Documentation</a>  </li>
<li><a href="https://www.elastic.co/docs/reference/edot-collector/config/authentication-methods">EDOT Collector Authentication Methods</a>  </li>
<li><a href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options">OpenTelemetry Protocol Exporter Configuration</a>  </li>
<li><a href="https://github.com/open-telemetry/opentelemetry-helm-charts">OpenTelemetry Collector Helm Chart</a>  </li>
<li><a href="https://www.elastic.co/docs/solutions/security/configure-elastic-defend">Elastic Defend</a></li>
</ul>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/claude-code-cowork-monitoring-otel-elastic</link>
    <guid isPermaLink="false">claude-code-cowork-monitoring-otel-elastic</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Spencer Niemi]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt563a09b2f5f5c4ca/6a7d7e16ead8ec694eba7aa9/claude-code-cowork-monitoring-otel-elastic.webp" length="0" type="image/webp"/>
    <pubDate>Sat, 25 Apr 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Elastic Security Integrations Roundup: Q1 2026]]></title>
    <description><![CDATA[Elastic Security Labs announces nine new integrations for Elastic Security spanning cloud security, endpoint visibility, email threat detection, identity and SIEM.]]></description>
    <content:encoded><![CDATA[<h2 id="aquarterlylookatelasticssecurityintegrationsecosystem">A quarterly look at Elastic’s security integrations ecosystem</h2>
<p>Security teams can only protect what they can see. Gaps in coverage, like a macOS fleet generating logs that never reach your SIEM, an email gateway running in isolation, or a cloud environment producing findings that stay siloed in the vendor console, are easily exploited by attackers.  </p>
<p>Elastic’s answer to this is continuous and open investment in third-party integrations, built on the belief that a strong security ecosystem requires deep integrations that make data from every corner of the stack searchable and contextualized. Today, we’re announcing nine new integrations for Elastic Security spanning cloud security, endpoint visibility, email threat detection, identity and SIEM.   </p>
<p>Each integration ships with ingest pipelines that normalize and structure data out of the box, along with prebuilt dashboards that serve as an immediate starting point for visualization and analysis, so teams can search, correlate and investigate across new data sources from day one without writing or maintaining parsers.</p>
<h2 id="macossecurityevents">macOS Security Events</h2>
<p>Elastic Defend, the native integration that delivers Elastic Endpoint Security, collects rich security telemetry on macOS, and it is intentionally focused on high-value detection signals rather than full system auditing. Login and logout events, account creation and deletion, service registration changes and application diagnostic logs all live outside that scope, leaving threat hunters and IR teams without complete macOS context. The macOS Security Events integration complements Elastic Defend, providing the same depth of OS-level visibility offered to Windows devices via the Windows Event Logs integration.</p>
<p>MacOS endpoints generate tens of thousands of unified log entries per endpoint. Left unfiltered, that volume creates noise rather than signals. This integration ships with predicate-based filters that scope ingestion to security-relevant events: authentication activity, process execution, network connections, file system changes, and system configuration modifications. </p>
<p>These predicate-based filters enable comprehensive macOS coverage without the cost or complexity of ingesting everything. Once ingested, these events are immediately available to Elastic Security’s AI Assistant. Analysts can ask natural-language questions like "Show me all privilege escalation attempts on macOS endpoints in the last 24 hours" or "Summarize login failures for this host”, turning raw unified log entries into actionable investigation context without writing a single query.</p>
<p>Check out the <a href="https://www.elastic.co/docs/reference/integrations/macos">macOS Security Events</a> integration.</p>
<h2 id="ibmqradar">IBM QRadar</h2>
<p>For teams running IBM QRadar in parallel with Elastic Security, alert ingestion into Elastic has become easier. The QRadar integration collects offense records from QRadar’s offense and rules endpoints, enriching each alert with the triggering rule’s name, ID, type and ownership, so analysts can triage in Elastic without switching back to QRadar. </p>
<p>This integration is the foundation of Elastic’s SIEM migration workflow for QRadar, which mirrors the capability already available for <a href="https://www.elastic.co/docs/reference/integrations/splunk">Splunk</a>. Teams can also use <a href="https://www.elastic.co/security-labs/from-qradar-to-elastic">Automatic Migration</a> for migrating their QRadar rules into Elastic. It uses semantic search and generative AI to map existing rules to Elastic’s 1,300+ prebuilt detections, and translates anything that doesn’t map directly into ES|QL, allowing you to consolidate your SIEM footprint without manually rebuilding your entire detection library. </p>
<p>Check out the <a href="https://www.elastic.co/docs/reference/integrations/ibm_qradar">IBM QRadar</a> integration.</p>
<h2 id="proofpointessentials">Proofpoint Essentials</h2>
<p>For Enterprise customers, Proofpoint’s TAP (Targeted Attack Protection) has been available in Elastic. To provide the same email threat visibility to SMB environments and the MSP and MSSPs who serve them, Proofpoint Essentials is now available.</p>
<p>The Proofpoint Essentials integration streams four event types into Elastic Security: </p>
<ul>
<li>Clicks on malicious URLs that were blocked  </li>
<li>Clicks that were permitted  </li>
<li>Messages blocked for containing threats recognized by URL Defense or Attachment Defense  </li>
<li>Messages delivered despite containing those threats</li>
</ul>
<p>To easily surface this data, two prebuilt dashboards are available:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt718b2adde02b169d/6a7d7f8e77b03468723fc623/image2.png" alt="Clicks Overview dashboard shows blocked versus permitted click trends over time, broken down by threat status and classification." title="Clicks Overview dashboard shows blocked versus permitted click trends over time, broken down by threat status and classification." />  </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte8f22253ce0da453/6a7d7f90dd26d2b71d2a7245/image1.png" alt="Threat Overview dashboard shows blocked versus permitted click trends over time, broken down by threat status and classification." title="Threat Overview dashboard shows blocked versus permitted click trends over time, broken down by threat status and classification." />  </p>
<p>For an SMB SOC team, this means phishing attempts, malware detections and policy violations land in the same platform as the rest of your security telemetry, removing the need to switch platforms to understand the full context of a threat. </p>
<p>Check out the <a href="https://www.elastic.co/docs/reference/integrations/proofpoint_essentials">Proofpoint Essentials</a> integration.</p>
<h2 id="awssecurityhub">AWS Security Hub</h2>
<p>AWS Security Hub aggregates findings across your AWS environment, but investigating those findings means staying inside the AWS console, separate from the rest of your team’s security data. The Elastic integration changes this by pulling Security Hub findings into Elastic in Open Cybersecurity Schema Framework (OCSF) format and normalizing them to ECS, offering schema-consistent data that’s immediately searchable via ES|QL.</p>
<p>Findings land in the <a href="https://www.elastic.co/docs/solutions/security/cloud/findings-page-3">Elastic Vulnerability Findings</a> page, integrating AWS cloud security posture directly into the workflows already in place. From there, you can correlate Security Hub data with signals from other sources - endpoint alerts, identity events, network telemetry - to build a fuller picture of risk across your AWS environment and investigate faster than the native console allows.</p>
<p>Check out the <a href="https://www.elastic.co/docs/reference/integrations/aws_securityhub">AWS Security Hub</a> integration.</p>
<h2 id="morenewelasticsecurityintegrations">More new Elastic Security integrations</h2>
<p>In addition to the featured integrations above, the following integrations are now available, each shipping with prebuilt dashboards for immediate value:</p>
<ul>
<li><a href="https://www.elastic.co/docs/reference/integrations/jupiter_one">JupiterOne</a>: Asset intelligence and cloud attack surface monitoring, ingesting cross-tool alerts, CVE findings, and threat detections enriched with MITRE ATT\&amp;CK mappings and CVSS scores, and host context for unified risk visibility.  </li>
<li><a href="https://www.elastic.co/docs/reference/integrations/airlock_digital">Airlock Digital</a>: Application allowlisting and execution control telemetry, capturing blocked process executions with command lines, file hashes and publisher context, so unauthorized execution attempts are visible and correlatable alongside the rest of your endpoint detections.   </li>
<li><a href="https://www.elastic.co/docs/reference/integrations/island_browser">Island Browser</a>: Enterprise browser security events spanning user navigation, device posture, compromised credential detection and admin activity, extending Elastic’s visibility to BYOD and unmanaged devices where traditional endpoint agents can’t be deployed.  </li>
<li><a href="https://www.elastic.co/docs/reference/integrations/ironscales">Ironscales</a>: AI-powered phishing detection events capturing email metadata, sender reputation, affected mailbox counts and suspicious links, correlatable with endpoint and identity data for faster investigation and response.   </li>
<li><a href="https://www.elastic.co/docs/reference/integrations/cyera">Cyera</a>: Data security posture management events, surfacing sensitive data risks including exposure severity, affected record counts, compliance framework violations, and datastore ownership across cloud environments, so sensitive data exposure doesn’t stay siloed in a separate DSPM console. </li>
</ul>
<h2 id="getstarted">Get started</h2>
<p>These integrations Elastic’s open approach to security. All nine integrations in this roundup ship with prebuilt dashboards and native ECS mappings, giving your team immediate visibility with no additional setup or custom visualization work required.</p>
<p>From there, findings, alerts and logs are immediately available to Elastic’s broader <a href="https://www.elastic.co/docs/solutions/security/ai/identify-investigate-document-threats">detection and investigation capabilities</a>: Attack Discovery for surfacing multi-stage threats, AI Assistant for natural-language investigation and guided response, and to ES|QL and EQL for custom detection and hunting queries.</p>
<ul>
<li><a href="https://www.elastic.co/integrations/data-integrations?solution=security">Browse available integrations</a>  </li>
<li><a href="https://www.elastic.co/blog/automatic-migration-ai-rule-translation">Learn about migrating to Elastic Security from other SIEMs</a></li>
</ul>
<p>Have questions or feedback? Join #security-siem in the <a href="https://www.elastic.co/community/">Elastic Stack Community Slack</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/elastic-security-integrations-roundup-q1-2026</link>
    <guid isPermaLink="false">elastic-security-integrations-roundup-q1-2026</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Carrie Pascale]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltff7595e3a127ed08/6a7d7f93b43770d4734d3f20/elastic-security-integrations-roundup-q1-2026.webp" length="0" type="image/webp"/>
    <pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Managing Elastic Security Detection Rules with Terraform]]></title>
    <description><![CDATA[Learn to define and deploy Elastic Security detection rules and exceptions using the Elastic Stack Terraform Provider vs detection-rules repository DaC capabilities.]]></description>
    <content:encoded><![CDATA[<p>At the core of Elastic Security lie <a href="https://www.elastic.co/blog/elastic-security-detection-engineering">outstanding detection capabilities</a>, allowing users to <a href="https://www.elastic.co/blog/elastic-security-building-effective-threat-hunting-detection-rules">create</a>, test, tune, manage, deploy detection rules, as code, in their environments. The ability to create robust detections is critical for Security Operations as detection logic elevates threat signal from the telemetry noise.</p>
<p>This article highlights how Elastic's new Terraform resources for security detection rules and exceptions expand practitioners' capabilities for detection-as-code deployment. Below you will find examples of defining and deploying your detection artifacts in Elastic Security with Terraform. We will also show how you can use Elastic's AI Agent to help quickly create the Terraform configuration for your custom rules. Finally, it also provides guidance on when to use the Elastic Stack Terraform <a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs/resources/kibana_security_detection_rule">provider</a> versus <a href="https://github.com/elastic/detection-rules/blob/main/README.md#detections-as-code-dac">tools from the detection-rules repository</a>.</p>
<h2 id="managingelasticwithterraform">Managing Elastic with Terraform</h2>
<p><a href="https://developer.hashicorp.com/terraform">Terraform is</a> a tool created by HashiCorp (now IBM) to manage infrastructure in the cloud, or in self-managed environments, as code. With a simple stroke of HCL (HashiCorp configuration language), users can define the desired state of their cloud provider infrastructure, application, configuration, and in Elastic’s case, cluster settings, configuration, indices or streams, and now also detection rules and alerts, as fully configurable, traceable, and reviewable code in your favorite source management tool.</p>
<p>The <a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs/resources/kibana_security_detection_rule">Elastic Stack Terraform provider</a> helps search, observability, and security professionals, as well as DevOps and SREs, configure their Elastic clusters with the right indices and mappings for their search use cases, SLOs or Fleet policies for their observability use case, and now, detection rules, alerts, and exceptions for their security use case. It can easily configure those, and many more objects and settings in the Elastic Stack. </p>
<h2 id="securitydetectionrulesnowascodewithterraform">Security Detection rules - now as code with Terraform</h2>
<p>With <a href="https://github.com/elastic/terraform-provider-elasticstack/releases/tag/v0.12.0">V0.12.0</a> and <a href="https://github.com/elastic/terraform-provider-elasticstack/releases/tag/v0.13.0">V0.13.0</a> of the <a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs/resources/kibana_security_detection_rule">Elastic Stack Terraform provider,</a> users can now manage their Detection rules and rule exceptions using Terraform. This is especially useful for users who have already been managing their Elastic deployments with Terraform and want to extend it to Detection rules.</p>
<h3 id="usingtheelasticstackterraformprovidertodeployrulesandexceptions">Using the Elastic Stack Terraform Provider to deploy Rules and Exceptions</h3>
<p>Let's look at an example of using the Elastic Stack Terraform Provider to deploy an Elastic Security Rule. In this example, we want to detect Windows Service Accounts that are performing an interactive logon on a host. </p>
<p>Service accounts typically have elevated privileges and rarely-rotated passwords, making them high-value targets for attackers. Since these accounts should only perform automated service logons, an interactive logon can indicate credential theft or misuse.</p>
<p>The first thing we need to think of is what telemetry we need to see which logons are happening on our host. <a href="https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4624">Logon events</a> are logged by the Windows Local Security Authority Subsystem Service (LSASS) whenever a logon session is successfully created on the machine. We can pick this up via an Elastic Agent with the <a href="https://www.elastic.co/docs/reference/integrations/windows">Windows Integration</a> installed. </p>
<p>The data will be written by the Elastic Agent into the system.security Data Stream, we can match it with this index pattern: <code>logs-system.security-*.</code> We also know that Logon events generate event code <code>4624</code> and that, in our example, the service account name starts with <code>svc</code> or ends with <code>$</code>.  In addition, an interactive login will have a logon type of <code>interactive</code>.</p>
<p>So, we can match these events with an <a href="https://www.elastic.co/docs/reference/query-languages/esql">ES|QL</a> rule like: </p>
<pre><code>FROM logs-system.security-\*  
| WHERE event.code \== "4624" AND (user.name LIKE "svc\_\*" OR user.name LIKE "svc-\*"  
     OR user.name LIKE "\*\_svc" OR user.name LIKE "\*$")  
     AND winlog.logon.type IN ("Interactive", "RemoteInteractive",  
         "CachedInteractive", "CachedRemoteInteractive")  
</code></pre>
<p>There may be situations where we don't want this rule to run, for example, if there is a legacy application that we want to permit interactive logons from. So, we can create an <a href="https://www.elastic.co/docs/solutions/security/detect-and-alert/rule-exceptions">Exception Item</a>, like: <code>user.name IS svc\_sqlbackup</code>. </p>
<p>Now that we know what we want the Rule and its Exceptions to look like, we can use the Terraform provider's <a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs/resources/kibana_security_detection_rule">elasticstack_kibana_security_detection_rule</a>, <a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs/resources/kibana_security_exception_list">elasticstack_kibana_security_exception_list</a>, and <a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs/resources/kibana_security_exception_item">elasticstack_kibana_security_exception_item</a> resources to define them in code. </p>
<p>Turning ES|QL rules into Terraform's configuration syntax, <a href="https://developer.hashicorp.com/terraform/language/syntax/configuration">HCL</a>, is a great use case for Elastic's <a href="https://www.elastic.co/docs/solutions/security/ai/agent-builder/agent-builder">AI Agent</a>.<br />
Elastic AI Agent capabilities help accelerate security operations across a wide range of tasks - from <a href="https://www.elastic.co/security-labs/speeding-apt-attack-discovery-confirmation-with-attack-discovery-workflows-and-agent-builder">alerts triage and incident response</a> to helping with detection lifecycle tasks. </p>
<p>Simply open AI Agent, and ask it to create Terraform configurations based on your query and exceptions. </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte5ea7e698a14d612/6a7d831ebd219851d67552f9/image2.png" alt="" /></p>
<p>You should end up with something like this: </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltca7adc2a6c26184c/6a7d8322c2e91402ef013cd5/image1.png" alt="" /></p>
<p>Here's a closer look at the code.</p>
<p>There are a few elements to call out specifically:</p>
<ul>
<li><code>type</code>: The type of exception list. For example: detection, endpoint, or endpoint_trusted_apps</li>
<li><code>namespace_type</code>: Determines whether the exception list is available in all Kibana spaces or just the single space in which it was created.</li>
</ul>
<pre><code>resource "elasticstack_kibana_security_exception_list" "svc_account_interactive_login" {
  list_id        = "svc-account-interactive-login-exceptions"
  name           = "Service Account Interactive Login Exceptions"
  description    = "Documented exceptions for service accounts that legitimately require interactive logon"
  type           = "detection"
  namespace_type = "single"
  tags           = ["service-accounts","windows","authentication"]
}  
</code></pre>
<p>This creates a new exception list.</p>
<p>Of note, the <code>entries</code> array contains the conditions under which the exception applies.</p>
<pre><code>resource "elasticstack_kibana_security_exception_item" "svc_sqlbackup" {
  list_id        = elasticstack_kibana_security_exception_list.svc_account_interactive_login.list_id
  item_id        = "svc-sqlbackup-exception"
  name           = "svc_sqlbackup - Legacy SQL Backup Agent"
  description    = "Approved exception: Legacy SQL backup agent requires interactive logon per vendor documentation."
  type           = "simple"
  namespace_type = "single"
  tags           = ["sql","backup","approved"]
entries = [
    {
      field    = "user.name"
      type     = "match"
      operator = "included"
      value    = "svc_sqlbackup"
    }
  ]
} 
</code></pre>
<p>This adds our exception: that we don't want the rule to run if the username is <code>svc\_sqlbackup</code>.</p>
<p>Of note, the elements from <code>enabled</code> to the <code>technique</code> array are examples of the other properties that can be set on a rule.</p>
<pre><code>resource "elasticstack_kibana_security_detection_rule" "svc_account_interactive_login" {
  name        = "Service Account Interactive Login"
  description = &lt;&lt;-EOT
    Detects interactive logins by service accounts. Service accounts should authenticate
    via service (Type 5) or batch (Type 4) logon types, not interactively. Interactive
    logins by service accounts may indicate credential theft or misuse.

    This rule identifies service accounts by common naming conventions (svc_*, svc-*,
    *_svc) and managed service accounts (*$).
  EOT

  type     = "esql"
  language = "esql"
  query    = &lt;&lt;-EOT
    FROM logs-system.security-* metadata _id, _version, _index
    | WHERE event.code == "4624"
      AND (user.name LIKE "svc_*" OR user.name LIKE "svc-*" OR user.name LIKE "*_svc" OR user.name LIKE "*$")
      AND winlog.logon.type IN ("Interactive", "RemoteInteractive", "CachedInteractive", "CachedRemoteInteractive")
    | KEEP @timestamp, host.name, user.name, user.domain, winlog.logon.type, source.ip, _id, _version, _index
  EOT

  enabled    = true 
  severity   = "high"
  risk_score = 73

  from     = "now-6m"
  to       = "now"
  interval = "5m"

  author  = ["Security Team"]
  license = "Elastic License v2"
  tags    = [
    "Domain: Endpoint",
    "OS: Windows",
    "Use Case: Identity and Access Audit",
    "Tactic: Initial Access",
    "Data Source: Windows Security Event Log"
  ]

  false_positives = [
    "Service accounts with documented exceptions that require interactive logon",
    "Break-glass procedures during incident response",
    "Initial service account configuration or troubleshooting"
  ]

  references = [
    "https://learn.microsoft.com/en-us/entra/architecture/service-accounts-on-premises",
    "https://blog.quest.com/10-microsoft-service-account-best-practices/",
    "https://attack.mitre.org/techniques/T1078/002/"
  ]

  threat = [
    {
      framework = "MITRE ATT&amp;CK"
      tactic = {
        id        = "TA0001"
        name      = "Initial Access"
        reference = "https://attack.mitre.org/tactics/TA0001/"
      }
      technique = [
        {
          id        = "T1078"
          name      = "Valid Accounts"
          reference = "https://attack.mitre.org/techniques/T1078/"
          subtechnique = [
            {
              id        = "T1078.002"
              name      = "Domain Accounts"
              reference = "https://attack.mitre.org/techniques/T1078/002/"
            }
          ]
        }
      ]
    }
  ]

  exceptions_list = [
    {
      id             = elasticstack_kibana_security_exception_list.svc_account_interactive_login.id
      list_id        = elasticstack_kibana_security_exception_list.svc_account_interactive_login.list_id
      namespace_type = elasticstack_kibana_security_exception_list.svc_account_interactive_login.namespace_type
      type           = elasticstack_kibana_security_exception_list.svc_account_interactive_login.type
    }
  ]
}
</code></pre>
<p>Finally, we define the rule, including the ES|QL query we provided earlier and MITRE ATT\&amp;CK classification.</p>
<p>You can add these resource definitions into one configuration file (perhaps security-rules.tf), add it to your <a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs#kibana">configured</a> Elastic Stack terraform directory, and then run the `terraform apply` command and parameter to deploy the Rule.</p>
<pre><code>terraform apply --auto-approve
</code></pre>
<p>Since <code>terraform apply</code> runs a plan before making changes, it will automatically detect if anyone has edited a rule directly in Kibana and show you exactly what drifted: no manual exports or diffs needed.</p>
<p>After Terraform has made the changes, we can see the Rule in Kibana: </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte66ac99b0a40cb26/6a7d8325bdcff04720c400a2/image5.png" alt="" /></p>
<p>We can also see the Exception List: </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb87fca154e808bcf/6a7d832805b7b530b9188b7e/image4.png" alt="" /></p>
<p>This way, you can define your detections in Terraform and benefit from automatic deployment along with other objects you manage with Terraform.</p>
<h2 id="terraformworkspacesformultispaceelasticdeployments">Terraform workspaces for multi-space Elastic deployments</h2>
<p>Terraform uses a concept called “<a href="https://developer.hashicorp.com/terraform/language/state/workspaces">workspaces</a>” allowing you to reuse the same infrastructure code for multiple deployments, for example, a dev, testing, and production environment. This concept is useful for managing rules across multiple deployments and/or Kibana spaces.</p>
<h2 id="managingdetectionswithterraformanddetectionsascode">Managing detections with Terraform and Detections as code</h2>
<p>Elastic also has <a href="https://www.elastic.co/security-labs/detection-as-code-timeline-and-new-features">Detections as Code functionality</a> available via our open <a href="https://github.com/elastic/detection-rules">detection-rules repository.</a> </p>
<p>The two tools have complementary strengths and are aligned with different user profiles and workflow stages for implementing Detections as Code.</p>
<h3 id="detectionascodefeaturesindetectionrules">Detection as Code features in detection-rules</h3>
<ul>
<li><strong>Best fit user profile</strong>: Detection engineers  </li>
<li><strong>Intended workflow phase</strong>: Rule authoring and validation</li>
</ul>
<p>With dual-sync between your GitHub repo and Kibana, linting, schema validation, and unit-testing, detection-rules functionality is well-suited to experienced Detection Engineers comfortable with Git-based version control.</p>
<h3 id="elasticstackterraformprovider">Elastic Stack Terraform Provider</h3>
<ul>
<li><strong>Best fit user profile</strong>: DevOps engineers / Platform teams  </li>
<li><strong>Intended workflow phase</strong>: Deployment and operations</li>
</ul>
<p>For users already using Terraform to manage their Elastic clusters, the Terraform Provider is a great fit, bringing consistency to all "x-as-code" operations and familiar state management and parameterization.</p>
<p>The key differences and optimal use cases for each tool are detailed in the comparison table below:</p>
<p>| Workflow Stage | detection-rules | Terraform Provider | Best Fit |
| :---- | :---- | :---- | :---- |
| <strong>Rule Authoring</strong> | Purpose-built tooling: create-rule wizard, TOML schema, KQL/EQL validation, field checks against ECS, Kibana-to-code export. | Standard HCL definitions; teams integrate their preferred validation tooling into existing pipelines. | <strong>detection-rules:</strong> Detection engineers authoring and refining rules daily. Teams wanting to automatically convert rules from Kibana into code. <strong>Terraform:</strong> Teams already using Terraform in their workflows, or teams wanting to automate and deploy detection rules as code, but without an established CI/CD platform. |
| <strong>Testing &amp; Validation</strong> | Built-in unit testing framework, schema validation, query validation, configurable test suites. | Terraform tests for optional unit testing. No built-in query validation: the provider relies on the Kibana API to accept or reject rule definitions at apply time. | <strong>detection-rules:</strong> Teams wanting out-of-the-box detection testing. <strong>Terraform:</strong> Platform teams managing rules as part of broader IaC with existing validation pipelines. Teams happy to write custom tests in Terraform. |
| <strong>Exception Management</strong> | Native exception list handling; export/import with rules, TOML storage, and rule linking. | Exception lists can be referenced via rule attributes. | <strong>detection-rules:</strong> Teams managing exceptions as part of detection content. <strong>Terraform:</strong> Teams managing exceptions as separate infrastructure resources. |
| <strong>Governance &amp; Drift Management</strong> | VCS-based with dual sync: push rules from repo to Kibana and export from Kibana back to repo, allowing either to serve as the source of truth. Drift detection is achievable with custom export-and-diff tooling. | VCS-authoritative: state file enforces declared configuration.  Native drift detection: Terraform plan surfaces any out-of-band changes made in Kibana.  | <strong>detection-rules:</strong> Teams comfortable with Git-based workflows and flexible sync models. <strong>Terraform:</strong> Organisations requiring formal state reconciliation and audit trails. |
| <strong>Rollback</strong> | Git history provides version control; re-import previous versions from the repo. | Revert HCL configuration in Git and re-apply to restore the previous state. | <strong>detection-rules:</strong> Teams using Git-centric recovery workflows. <strong>Terraform:</strong> Organisations with standardised rollback mechanisms across infrastructure and rulesets. |
| <strong>Parameterisation &amp; Templating</strong> | Achievable with external preprocessing (Jinja2, etc.) before import. | Native HCL features: variables, locals, for_each, dynamic blocks, and modules. | <strong>detection-rules:</strong> Teams not requiring parameterisation or with existing templating solutions.  <strong>Terraform:</strong> Teams wanting native IaC parameterisation. |
| <strong>Operational Integration</strong> | Focused tooling optimised for detection engineering workflows. | Unified control plane managing detection rules alongside cloud infrastructure, network policies, and other security tooling.  Integrates with other resources that may be required by detections such as external connectors. | <strong>detection-rules:</strong> Specialist detection teams. More flexible if dual-sync (Kibana and repo are both sources of truth).  <strong>Terraform:</strong> Platform teams managing Elastic as part of broader infrastructure. |</p>
<p>In short, Detection Engineers are better served by the specialized creation and testing tools provided in the <code>detection-rules</code> repository, while DevOps/Platform Teams should use the Terraform provider to manage detection rules as part of their broader infrastructure-as-code strategy for deployment and operations.</p>
<h2 id="tryitout">Try it out</h2>
<p>To experience the full benefits of what Elastic has to offer for detection engineers, upgrade to 9.3 or start your Elastic Security <a href="https://cloud.elastic.co/registration">free trial</a>. Visit <a href="https://www.elastic.co/security">elastic.co/security</a> to learn more and get started.</p>
<p><em>The release and timing of any features or functionality described in this post remain at Elastic's sole discretion. Any features or functionality not currently available may not be delivered on time or at all.</em></p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/managing-rules-with-terraform</link>
    <guid isPermaLink="false">managing-rules-with-terraform</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Kseniia Ignatovych,Omer Kushmaro,Stuart Moorhouse,Marc-Antoine Leclercq]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdb962033314a1e56/6a7d832b3cab1c14f60e1a36/managing-rules-with-terraform.png" length="0" type="image/png"/>
    <pubDate>Fri, 13 Mar 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Manage your Elastic security stack as code with the Elastic Stack Terraform provider]]></title>
    <description><![CDATA[From detection rules to AI connectors - the latest Terraform provider releases bring security, observability, and ML capabilities to your infrastructure-as-code workflows.]]></description>
    <content:encoded><![CDATA[<p>The <a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs">Elastic Stack Terraform provider</a> has reached a significant milestone. Starting with release v0.13.1, you can manage your Elastic security posture - detection rules, exception lists, and prebuilt rules - alongside ML anomaly detection jobs, synthetics monitors, and AI connectors, all as code.</p>
<p>This brings your detection logic and ML jobs into the same versioned, peer-reviewed workflow as your core clusters. It ensures your security posture and AI connectors are no longer manual outliers in an otherwise automated environment.</p>
<h2 id="thechallengesecurityandobservabilityconfigurationatscale">The challenge: Security and observability configuration at scale</h2>
<p>As Elastic deployments grow, so does the complexity of managing them. Security teams maintain hundreds of detection rules. SREs configure monitoring across dozens of clusters. ML engineers tune anomaly detection jobs across multiple environments. All of these configurations must be consistent, auditable, and reproducible.</p>
<p>Without infrastructure as code, teams face two problems:</p>
<ol>
<li><p><strong>Configuration drift.</strong> Rules, policies, and monitors are created manually through the Kibana UI. Over time, production and staging diverge. No one is sure which version of a detection rule is running where.  </p></li>
<li><p><strong>Buried audit trail.</strong> When a detection rule changes or an exception is added, there's no pull request to review, no commit history to trace, and no rollback path if something breaks. Users need to put in extra effort to access such history.</p></li>
</ol>
<p><a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs">Elastic Stack Terraform provider</a> solves this by bringing these configurations into the same version-controlled, peer-reviewed workflow that teams already use for infrastructure.</p>
<h2 id="securityartifactsascodedetectionrulesexceptionsandprebuiltrules">Security artifacts as code: Detection rules, exceptions, and prebuilt rules</h2>
<p>You can now manage the full lifecycle of Elastic Security detection rules through Terraform.</p>
<h3 id="detectionrules">Detection rules</h3>
<p>The <code>elasticstack_kibana_security_detection_rule</code> resource lets you define, version, and deploy detection rules in the <a href="https://github.com/hashicorp/hcl">HashiCorp Configuration Language</a> (HCL) format:</p>
<pre><code>resource "elasticstack_kibana_security_detection_rule" "suspicious_admin_logon" {
  name        = "Suspicious Admin Logon Activity"
  type        = "query"
  query       = "event.action:logon AND user.name:admin"
  language    = "kuery"
  enabled     = true
  description = "Detects suspicious admin logon activities"
  severity    = "high"
  risk_score  = 75
  from        = "now-6m"
  to          = "now"
  interval    = "5m"
  tags        = ["security", "authentication", "admin"]
}
</code></pre>
<p>This means your detection rules live in Git, undergo code review, and are deployed consistently across environments. No more clicking through the Kibana UI to replicate rules from staging to production.</p>
<p><a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs/resources/kibana_security_detection_rule">Detection rule resource docs</a></p>
<h3 id="exceptionlistsanditems">Exception lists and items</h3>
<p>The security-as-code story extends to a full suite of exception management resources:</p>
<ul>
<li><code>elasticstack_kibana_security_exception_list</code> - Create and manage exception lists  </li>
<li><code>elasticstack_kibana_security_exception_item</code> - Define individual exception items within a list  </li>
<li><code>elasticstack_kibana_security_list</code> and <code>elasticstack_kibana_security_list_item</code> - Manage value lists for IP allowlists, file hashes, and other indicators  </li>
<li><code>elasticstack_kibana_security_list_data_streams</code> - Associate lists with specific data streams</li>
</ul>
<p>Here's an example that ties them together - an exception list with items that suppress known false positives for a detection rule:</p>
<pre><code>resource "elasticstack_kibana_security_exception_list" "vuln_scanner_exceptions" {
  list_id        = "vuln-scanner-exceptions"
  name           = "Vulnerability Scanner Exceptions"
  description    = "Suppress alerts from authorized vulnerability scanners"
  type           = "detection"
  namespace_type = "single"
  tags           = ["security", "vulnerability-scanning"]
}

resource "elasticstack_kibana_security_exception_item" "nessus_scanner" {
  list_id        = elasticstack_kibana_security_exception_list.vuln_scanner_exceptions.list_id
  item_id        = "nessus-scanner"
  name           = "Nessus Scanner - Authorized"
  description    = "Suppress alerts from authorized Nessus scanner hosts"
  type           = "simple"
  namespace_type = "single"

  entries = [
    {
      type     = "match"
      field    = "source.ip"
      operator = "included"
      value    = "10.0.50.10"
    },
    {
      type     = "match_any"
      field    = "process.name"
      operator = "included"
      values   = ["nessus", "nessusd"]
    }
  ]

  tags = ["nessus", "authorized-scanner"]
}

resource "elasticstack_kibana_security_exception_item" "qualys_scanner" {
  list_id        = elasticstack_kibana_security_exception_list.vuln_scanner_exceptions.list_id
  item_id        = "qualys-scanner"
  name           = "Qualys Scanner - Authorized"
  description    = "Suppress alerts from authorized Qualys scanner subnet"
  type           = "simple"
  namespace_type = "single"

  entries = [
    {
      type     = "match"
      field    = "source.ip"
      operator = "included"
      value    = "10.0.51.0/24"
    }
  ]

  tags = ["qualys", "authorized-scanner"]
}
</code></pre>
<p>The exception list and its items are linked by <code>list_id</code>, so Terraform manages the dependency graph automatically. Adding a new authorized scanner is a one-line PR - no clicking through the Kibana UI, no risk of forgetting which environment got the update.</p>
<h3 id="prebuiltsecurityrules">Prebuilt security rules</h3>
<p>The <code>elasticstack_kibana_prebuilt_rule</code> resource lets you manage Elastic's prebuilt detection rules via Terraform. This is particularly valuable for organizations that need to track which prebuilt rules are enabled, customize their parameters, and ensure consistent deployment across environments.</p>
<h2 id="mlanomalydetectionascode">ML anomaly detection as code</h2>
<p>Machine learning anomaly detection is one of Elasticsearch's most powerful capabilities - but managing ML jobs across environments has traditionally been a manual process. You create a job in the Kibana UI, tune the detectors, configure the datafeed, and hope someone documents the settings so they can be replicated in the next environment.</p>
<p>The <code>elasticstack_elasticsearch_ml_anomaly_detection_job</code> resource changes that. You can now define the full configuration of an anomaly detection job in HCL - detectors, bucket spans, influencers, data feeds, and analysis limits - and deploy it consistently across dev, staging, and production.</p>
<pre><code>resource "elasticstack_elasticsearch_ml_anomaly_detection_job" "cpu_anomalies" {
  job_id      = "high-cpu-by-host"
  description = "Detect unusual CPU usage patterns"

  analysis_config = {
    bucket_span = "15m"
    detectors   = [{
      function   = "high_mean"
      field_name = "system.cpu.user_pct"
    }]
    influencers = ["host.name"]
  }

  data_description = {
    time_field = "@timestamp"
  }
}
</code></pre>
<p>This matters for teams that rely on ML to catch infrastructure anomalies, unusual user behavior, or security threats. Instead of manually recreating jobs when spinning up new clusters or recovering from failures, the entire ML configuration lives in version control - reviewable, repeatable, and recoverable.</p>
<h2 id="crossclusterautomationwithapikeys">Cross-cluster automation with API keys</h2>
<p>For organizations running multiple Elasticsearch clusters, the provider now supports <strong>cluster API keys for cross-cluster search (CCS) and cross-cluster replication (CCR)</strong>. You can create API keys specifically designed for secure cross-cluster communication, enabling end-to-end automation of multi-cluster architectures.</p>
<p>This means you can provision two clusters, configure CCS/CCR between them, and set up the necessary security credentials - all in a single Terraform configuration.</p>
<pre><code>resource "elasticstack_elasticsearch_security_api_key" "ccs_key" {
  name = "cross-cluster-search-key"
  type = "cross_cluster"

  access = {
    search = [{
      names = ["logs-*", "metrics-*"]
    }]
    replication = [{
      names = ["archive-*"]
    }]
  }

  expiration = "90d"

  metadata = jsonencode({
    environment = "production"
    purpose     = "ccs-ccr-between-prod-clusters"
    team        = "platform"
  })
}
</code></pre>
<p>When the <code>type</code> is set to <code>cross_cluster</code>, the API key is scoped to CCS/CCR operations. You define which index patterns are accessible for search and replication, set an expiration policy, and tag the key with metadata - all reviewable in a pull request.</p>
<p>Learn more about <a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs/resources/elasticsearch_security_api_key">API key resources</a> in the documentation.</p>
<h2 id="aiconnectorsascode">AI connectors as code</h2>
<p>The provider now supports <code>.bedrock</code> and <code>.gen-ai</code> connectors, bringing AI infrastructure into your Terraform workflows. As teams increasingly integrate large language models into their Elastic workflows - for AI assistants, attack discovery, and automated investigations - managing these connector configurations as code becomes essential.</p>
<pre><code>resource "elasticstack_kibana_action_connector" "bedrock" {
  name              = "aws-bedrock"
  connector_type_id = ".bedrock"
  config = jsonencode({
    apiUrl       = "https://bedrock-runtime.us-east-1.amazonaws.com"
    defaultModel = "anthropic.claude-v2"
  })
  secrets = jsonencode({
    accessKey = var.aws_access_key
    secret    = var.aws_secret_key
  })
}

resource "elasticstack_kibana_action_connector" "openai" {
  name              = "openai"
  connector_type_id = ".gen-ai"
  config = jsonencode({
    apiProvider  = "OpenAI"
    apiUrl       = "https://api.openai.com/v1/chat/completions"
    defaultModel = "gpt-4"
  })
  secrets = jsonencode({
    apiKey = var.openai_api_key
  })
}
</code></pre>
<p>With these connectors defined in Terraform, you can version your AI integration configuration alongside the rest of your Elastic infrastructure - and swap models or providers through a simple PR.</p>
<h2 id="observabilityenhancements">Observability enhancements</h2>
<h3 id="syntheticsmonitors">Synthetics monitors</h3>
<p>The <code>elasticstack_kibana_synthetics_monitor</code> resource now includes a <code>labels</code> field, enabling better organization and filtering of synthetic checks. Labels let you tag monitors by team, environment, or service, making it easier to manage synthetic monitoring at scale.</p>
<h2 id="additionalplatformimprovements">Additional platform improvements</h2>
<p>Recent releases also included several resources and attributes that round out the provider's coverage:</p>
<ul>
<li><code>elasticstack_elasticsearch_alias</code> - Manage Elasticsearch aliases as a dedicated resource  </li>
<li><code>elasticstack_kibana_default_data_view</code> - Set the default data view for a Kibana space  </li>
<li><code>solution</code> attribute on <code>elasticstack_kibana_space</code> - Configure the solution type for Kibana spaces (available from 8.16)  </li>
<li>Fleet agent policy enhancements - <code>host_name_format</code> for configuring hostname vs. FQDN, and <code>required_versions</code> for version pinning</li>
</ul>
<h2 id="gettingstarted">Getting started</h2>
<p>If you're already using the Elastic Stack Terraform provider, upgrade to the latest provider version to get all of these capabilities:</p>
<pre><code>terraform {
  required_providers {
    elasticstack = {
      source  = "elastic/elasticstack"
      version = "~&gt; 0.14"
    }
  }
}
</code></pre>
<p>If you're new to managing your Elastic Stack with Terraform, start with the <a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs">provider documentation</a> on the Terraform registry.</p>
<p>To start using Elastic Cloud today, log in to the <a href="https://cloud.elastic.co/">Elastic Cloud console</a> or sign up for a <a href="https://cloud.elastic.co/registration">free trial</a>.<br />
For the full set of changes, check out the <a href="https://github.com/elastic/terraform-provider-elasticstack/releases">release notes on GitHub</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/manage-elastic-with-terraform</link>
    <guid isPermaLink="false">manage-elastic-with-terraform</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Omer Kushmaro]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt539b15b72da34a58/6a7d83195588adfd9bee4332/manage-elastic-with-terraform.png" length="0" type="image/png"/>
    <pubDate>Fri, 27 Feb 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Automating GOAD and Live Malware Labs]]></title>
    <description><![CDATA[Stop building labs by hand. Automate the deployment of a fully instrumented Purple Team range using Ludus and Elastic Security. Spin up infrastructure, execute attacks, and validate detection rules in a single, repeatable workflow.]]></description>
    <content:encoded><![CDATA[<h2 id="introductiontheneedforascalableautomatedsimulationrange"><strong>Introduction: The Need for a Scalable, Automated Simulation Range</strong></h2>
<p>In modern security operations, detection engineering is no longer a “set it and forget it” discipline. The central challenge for any security team – and the question that underpins the entire purple-team approach is simple: <em>how do you know whether your detection rules genuinely work?</em> Continually validating detection logic against an ever-shifting adversary toolkit is now a fundamental requirement.</p>
<p>Arguably, the largest hurdle for this exercise has always been setting up the lab. Manually provisioning a multi-domain Active Directory forest, configuring it with specific vulnerabilities, and deploying a separate, contained malware analysis environment is a complex and time-consuming process. This repetitive setup work is a significant drain on an organization's most valuable resource: the time of its senior security analysts. Community discussions echo this frustration, highlighting the hours lost to manual setup before a single test can be run.</p>
<p>This blog details a modern solution that eliminates this bottleneck by combining rapid infrastructure automation with a unified security analytics platform. The solution leverages two key components:</p>
<ol>
<li><a href="https://ludus.cloud/"><strong>Ludus</strong></a><strong>:</strong> An open-source automation overlay that deploys and configures complex, multi-VM cyber ranges from a single command.  </li>
<li><a href="https://www.elastic.co/security"><strong>Elastic Security</strong></a><strong>:</strong> The platform that unifies Security Information Event Management (SIEM), eXtended Detection and Response (XDR), and cloud security, providing a consolidated solution to ingest, detect, and respond to threats. It offers the "limitless visibility" required to observe every action within the simulated environment.</li>
</ol>
<p>The goal of this guide is to provide a definitive, step-by-step blueprint for building this integrated system. It will show how to move from slow, manual, and inconsistent lab testing to a continuous, automated, and scalable detection-engineering workflow beyond what <a href="https://github.com/elastic/cortado">Elastic Cortado</a> provides. </p>
<h2 id="thesolutionarchitectureluduselastic"><strong>The Solution Architecture: Ludus + Elastic</strong></h2>
<p>This architecture represents a high-fidelity simulation of a modern hybrid enterprise. The Ludus range acts as the "on-prem" or IaaS data center, while the Elastic Cloud deployment represents the "SaaS" security stack. This model perfectly mirrors the hybrid and multi-cloud environments that Elastic Security is designed to protect, making the <em>architecture</em> of the test as valuable as the attacks themselves.</p>
<p>The build consists of the following core components.</p>
<p>| Component |  | Technology | Function |
| :---- | ----- | :---- | :---- |
| <strong>Foundation (</strong>Infrastructure<strong>)</strong> |  | <strong>Ludus</strong> (Proxmox/Ansible) | Deploys VM ranges from a single YAML config. |
| <strong>Targets</strong> |  | <strong>Identity - GOAD</strong> (Windows Server) <strong>Supply Chain - XZbot</strong> (Debian) | Multi-domain AD forest with intentional vulnerabilities (Kerberoasting, Print Nightmare). Linux host infected with CVE-2024-3094 for supply chain simulation. |
|  |  |  |  |
| <strong>The Sensor Grid (</strong>Visibility<strong>)</strong> |  | <strong>Elastic Agent</strong> | Unified telemetry collection (EDR + Logs). |
| <strong>The Brain (</strong>Analysis<strong>)</strong> |  | <strong>Elastic Security</strong> | SIEM/XDR platform for correlation and AI-driven investigation. |</p>
<h3 id="component1thefoundationludus"><strong>Component 1: The Foundation (Ludus)</strong></h3>
<p>Ludus serves as the Infrastructure-as-a-Service (IaaS) layer. Built to run on Proxmox 8/9 or Debian 12/13, it uses YAML configuration files to define complex virtual networks, supporting up to 255 distinct VLANs. Behind the scenes, Ludus easily leverages Packer and Ansible to build, configure, and deploy the virtual machine templates from that single file.<br />
Review and follow the installation steps and hardware requirements in the Ludus <a href="https://docs.ludus.cloud/docs/quick-start/install-ludus">quick-start</a>. </p>
<h3 id="component2thetargetsthelabs"><strong>Component 2: The Targets (The Labs)</strong></h3>
<p>This guide merges two distinct Ludus environments into a single, comprehensive range to test a wider spectrum of threats:</p>
<ul>
<li><a href="https://github.com/Orange-Cyberdefense/GOAD"><strong>Game of Active Directory (GOAD)</strong></a><strong>:</strong> A purpose-built Active Directory lab designed by security researchers at <a href="https://www.orangecyberdefense.com/">Orange Cyberdefense</a>. It is pre-configured with the specific misconfigurations and vulnerabilities needed to simulate common identity-based attack paths, such as Kerberoasting, NTLM Relay, and Active Directory Certificate Services (ADCS) abuse.  </li>
<li><a href="https://docs.ludus.cloud/docs/environment-guides/malware-lab"><strong>XZbot Malware Lab</strong></a><strong>:</strong> A high-risk, high-fidelity malware environment. This lab contains the <em>actual, functional</em> CVE-2024-3094 backdoor. This provides a perfect, modern test case for a sophisticated software supply-chain attack.</li>
</ul>
<h4 id="importantdisclaimer">Important Disclaimer</h4>
<p>Handling live malware, even for research, can violate Acceptable Use Policies (AUPs) of ISPs or cloud providers. Ensure you own the infrastructure (Ludus is on-prem) and ensure your upstream ISP allows for such research, or route traffic through a VPN.</p>
<h3 id="component3thesensorgridelasticagentdefend"><strong>Component 3: The Sensor Grid (Elastic Agent &amp; Defend)</strong></h3>
<p>To gain visibility, every virtual machine in the Ludus range across both GOAD and XZbot labs will be instrumented with <strong>Elastic Agent</strong>, a single, unified agent for data collection and protection (via Elastic Defend).</p>
<p>This instrumentation is automated via the <a href="https://github.com/badsectorlabs/ludus_elastic_agent"><em>badsectorlabs/ludus_elastic_agent</em></a> Ansible role. This role is the critical lynchpin that programmatically bridges the infrastructure provisioning phase (Ludus/Ansible) with the security instrumentation phase (Elastic), enabling a true "infrastructure-as-code" workflow.</p>
<p>Crucially, the Elastic Agent policy will be configured with the <strong>Elastic Defend</strong> integration. This elevates the agent from a simple log collector to a full-powered Endpoint Detection &amp; Response (EDR)/eXtended Detection &amp; Response (XDR) solution, providing host-based detections (including Machine Learning (ML) driven malware and ransomware detection) and the deep, kernel-level telemetry essential for detection.</p>
<p><em>Note: For the purple team approach outlined in this blog, set policies to <strong>Detect</strong> mode.</em> </p>
<h3 id="component4thebrainelasticcloudhostedelasticserverless"><strong>Component 4: The Brain (Elastic Cloud Hosted / Elastic Serverless)</strong></h3>
<p>All security telemetry and alerts from the Elastic Agents in the Ludus range are streamed to a centralized <strong>Elastic Cloud Hosted (ECH)</strong> or <strong>Elastic Serverless</strong> deployment. This is where the unified platform's analytical power comes to life. Using a cloud-native platform is not just for hosting; it is what unlocks Elastic's most advanced, force-multiplying features, including <strong>Attack Discovery</strong> and the <strong>AI Assistant</strong>. <a href="https://cloud.elastic.co/registration">Click here to start a trial on Elastic Cloud</a>. </p>
<p>The diagram below provides an overview of the build, which is based on the <a href="https://github.com/Orange-Cyberdefense/GOAD">GOAD lab</a>.  </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt28906c1e14eed213/6a7d7dc53ce8e25c3dcf25ea/image8.png" alt="" /></p>
<h2 id="phase1buildingandinstrumentingtherange"><strong>Phase 1: Building and Instrumenting the Range</strong></h2>
<p>This section provides a technical, step-by-step guide to configuring and deploying the automated range. The process follows a clear "infrastructure-as-code" (IaC) model, where the security instrumentation is defined alongside the infrastructure itself, ensuring a consistent and repeatable monitoring posture for every deployment. The Elastic Cloud instance and its configurations can be managed with the <a href="https://registry.terraform.io/providers/elastic/ec/latest/docs">Elastic Cloud</a> and <a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs">Elastic Stack</a> Terraform provider for a full IaC model of the range and the SIEM. </p>
<h3 id="31configuringtheelasticagentpolicyinkibana"><strong>3.1 Configuring the Elastic Agent Policy (in Kibana)</strong></h3>
<p>Before running the Ludus range deployment, the agent policy must be created in the Elastic Cloud instance. This policy is what enables the powerful EDR/XDR telemetry.</p>
<p>The operational flow is as follows:</p>
<ol>
<li>Log in to the Elastic Cloud (ECH) or Elastic Serverless Kibana instance.  </li>
<li>Navigate to <strong>Management &gt; Fleet</strong>.  </li>
<li><a href="https://www.elastic.co/docs/reference/fleet/agent-policy#create-a-policy">Create a new <strong>Agent policy</strong></a> (e.g., "ludus-range-policy"). <em>The ludus_elastic_agent role will enroll agents into the policy you specify in your VM-level customization or into the default policy linked to the global variable.</em>  </li>
<li><a href="https://www.elastic.co/docs/reference/fleet/agent-policy#add-integration">Add the <strong>Elastic Defend</strong> integration</a> to this policy.  </li>
<li><a href="https://www.elastic.co/docs/solutions/security/configure-elastic-defend/configure-an-integration-policy-for-elastic-defend">Configure the Elastic Defend integration</a> to run in <strong>Detect</strong> mode. This activates the full suite of EDR telemetries.  </li>
<li>Save the policy and click "Add agent." This will provide the <strong>Enrollment token</strong> (for ludus_elastic_enrollment_token) and <strong>Fleet server URL</strong> (for ludus_elastic_fleet_server) needed for the ludus.yml file.  </li>
<li>(<strong><em>Optional</em></strong>) Repeat steps 3-6 to create customized policies to align with the host’s functions and capabilities for VM-level customization of policies. </li>
</ol>
<p>Once this policy is created and the token is pasted into the ludus.yml file, running Ludus range deploy will execute the full, automated workflow. Ludus provisions the VMs, and Ansible installs the Elastic Agent, which then enrolls in Fleet and automatically pulls down the policy containing the Elastic Defend integration. This provides the rich EDR telemetry - kernel-level process, file, network, and registry events - from the moment the lab is born.</p>
<h3 id="32theludusyamlconfigurationludusyml"><strong>3.2 The Ludus YAML Configuration (ludus.yml)</strong></h3>
<p>Ludus provides the steps to deploy the GOAD range <a href="https://docs.ludus.cloud/docs/environment-guides/goad">here</a>. The configuration for the range is stored in the ludus.yml configuration file. For the GOAD range, it is located in <code>ad/GOAD/providers/ludus/config.yml</code>.<br />
The full configuration in the appendix is an example based on a sample running configuration that merges a full GOAD lab (on VLAN 10) with the XZbot lab (on VLAN 20). </p>
<p>To deploy a customized version during installation, update the <code>ad/GOAD/providers/ludus/config.yml</code> file before running the <code>goad.sh</code> script in <a href="https://docs.ludus.cloud/docs/environment-guides/goad#2-on-the-ludus-host-clone-and-setup-the-goad-project">step 2</a>.</p>
<pre><code>git clone https://github.com/Orange-Cyberdefense/GOAD.git
cd GOAD
sudo apt install python3.11-venv
export LUDUS_API_KEY='myapikey'  # put your Ludus admin api key here nano ad/GOAD/providers/ludus/config.yml # customize the configuration here
./goad.sh -p ludus
GOAD/ludus/local &gt; check
GOAD/ludus/local &gt; set_lab GOAD # GOAD/GOAD-Light/NHA/SCCM
GOAD/ludus/local &gt; install
</code></pre>
<p>Two key configuration options can be used to customize the range:</p>
<ol>
<li><p><strong>Global Variables:</strong> To simplify the config and avoid repetition, the Elastic Agent variables are defined <em>once</em> at the top level in a global Ansible.vars block and are inherited by all VMs. </p>
<p><em>The enrollment token determines the Elastic Agent policy used.</em></p></li>
</ol>
<pre><code># ludus.yml
---
# --- GLOBAL ANSIBLE VARS (Simplification) ---
# Define Elastic agent vars once and apply globally
global_role_vars:
  ludus_elastic_fleet_server: "&lt;your-fleet.example.com:443&gt;" # Use 443 for cloud
  ludus_elastic_enrollment_token: "&lt;your_enrollment_token&gt;"
  ludus_elastic_agent_version: "9.2.1"
</code></pre>
<ol>
<li><strong>VM-level Variables:</strong> The Elastic Agent variables can be configured at the VM-level to customize the policy applied. These can be combined with the global variable, for example, where the agent version and fleet_server are set via global variables, and the enrollment tokens are set at the VM-level to apply different policies to VMs.</li>
</ol>
<pre><code># --- VM DEFINITIONS ---
vms:
  # --- GOAD LAB (VLAN 10) ---
  - name: "{{ range_id }}-GOAD-DC01"
    hostname: "{{ range_id }}-DC01"
    template: win2019-server-x64-template
    vlan: 10
    ip_last_octet: 10
    ram_gb: 4
    cpus: 2
    windows: { sysprep: true }
    ansible:
      roles:
        - badsectorlabs.ludus_elastic_agent
      role_vars:
        ludus_elastic_enrollment_token: "&lt;your_enrollment_token&gt;" # different token for different policies
  # (Definitions for GOAD-DC02, GOAD-DC03, GOAD-SRV02, GOAD-SRV03 
  #  would follow, all inheriting the global ansible vars)
</code></pre>
<h4 id="automatingelasticagentdeployment">Automating Elastic Agent Deployment</h4>
<p>The ludus.yml snippet above demonstrates the automation. By adding the <code>badsectorlabs.ludus_elastic_agent</code> role to the ansible.roles section of each VM definition, Ludus will automatically install and configure the agent during deployment.</p>
<p>This single Ansible role is compatible with all operating systems in our heterogeneous lab, including Windows (for GOAD), Kali, and Debian (for XZbot).</p>
<p>As shown in the simplified YAML, the ansible.vars block at the top level passes the critical parameters to the role:</p>
<ul>
<li>ludus_elastic_fleet_server: The Fleet server URL and port for your Elastic Cloud deployment (e.g., your-fleet.example.com:443).  </li>
<li>ludus_elastic_enrollment_token: The token that enrolls the agent.<br />
The full example sets the ludus_elastic_enrollment_token at the VM level to demonstrate the ability to use different policies.   </li>
<li>ludus_elastic_agent_version: The specific agent version to install (e.g., 9.2.1).</li>
</ul>
<p><em>Note: The Kali host will have Elastic Defend also deployed to monitor attacker behavior, this won’t be possible in a real-world scenario.</em></p>
<h2 id="safetyfirstisolationopsecandlivemalware"><strong>Safety First: Isolation, OPSEC, and Live Malware</strong></h2>
<p>This section contains a critical safety and operational security (OPSEC) warning. This configuration involves a significant, non-trivial risk that must be professionally managed.</p>
<h3 id="41thethreatthisisnotasimulation"><strong>4.1 The Threat: This is Not a Simulation</strong></h3>
<p>It must be stated unequivocally: The Ludus XZbot lab guide and its associated Ansible role install the <strong>actual, functional CVE-2024-3094 backdoor</strong>. This is not benign, simulated code. The lab's own documentation states: "Danger: This role contains malware (on purpose)."</p>
<p>While described as a "passive backdoor" (meaning it requires an attacker to actively trigger it), any virtual machine running this code with an open internet connection is a catastrophic liability. It could be scanned, exploited by unknown actors, or used as a pivot point to attack other networks.</p>
<h3 id="42thecontradictionisolationvscloudconnectivity"><strong>4.2 The Contradiction: Isolation vs. Cloud Connectivity</strong></h3>
<p>This architecture creates a direct and critical operational conflict:</p>
<ol>
<li><strong>Requirement 1 (Safety):</strong> The malware lab <em>must</em> be isolated from the public internet to prevent compromise or breakout.  </li>
<li><strong>Requirement 2 (Function):</strong> The Elastic Agent <em>must</em> have outbound internet connectivity to reach the Elastic Cloud Hosted / Elastic Serverless endpoints for enrollment and data streaming.</li>
</ol>
<p>A novice user would fail here, either by exposing their infected lab to the world or by isolating it so completely that no security telemetry can be collected.</p>
<h3 id="43thesolutionpinholeegressvialudustestingmode"><strong>4.3 The Solution: Pinhole Egress via Ludus Testing mode</strong></h3>
<p>The conflict is resolved using Ludus's built-in "<a href="https://docs.ludus.cloud/docs/networking#testing-mode">testing</a>" mode, which provides granular control over network egress. This feature is used for the pinhole egress, which enables agent control, telemetry, and log output.</p>
<pre><code># 1. Start the isolated testing session
ludus testing start # Note external DNS resolvers may also need to be added # ludus testing allow -i 1.1.1.1,8.8.8.8

# 2. Allow Elastic Fleet Server (Control Plane)
# Replace &lt;id&gt; with your specific deployment ID # Note the endpoint will differ based on the cloud providers
ludus testing allow -d &lt;your-deployment-id&gt;.fleet.us-central1.gcp.cloud.es.io

# 3. Allow Elasticsearch Ingest (Data Plane) # Note the endpoint will differ based on the cloud providers
ludus testing allow -d &lt;your-deployment-id&gt;.es.us-central1.gcp.cloud.es.io
</code></pre>
<p>This configuration delivers an expert-level solution: the malware is safely contained, while the Elastic Agent is granted only the minimal connectivity required to make policy updates (via communication with the <code>fleet</code> endpoint) and to ingest data (via communication with the <code>ES</code> endpoint).</p>
<h3 id="44accessingtherangeintestingmodewireguard"><strong>4.4 Accessing the Range in Testing Mode (WireGuard)</strong></h3>
<p>Once Testing Mode is active, standard routing fails. You cannot simply SSH into your Kali VM from your local LAN because the router drops the traffic. Ludus provides an out-of-band management channel using WireGuard.</p>
<p>Ludus configures a WireGuard interface (wg0) on the router VM (198.51.100.1) and assigns you a static client IP (e.g., 198.51.100.2).</p>
<ul>
<li><strong>Persistent Allow Rules:</strong> The router's firewall configuration includes specific rules in the LUDUS_DEFAULTS chain. These rules explicitly <strong>ACCEPT</strong> traffic sourced from or destined to the WireGuard subnet (198.51.100.0/24).  </li>
<li><strong>Priority:</strong> Because these rules exist in the LUDUS_DEFAULTS chain, they override the DROP rules applied by Testing Mode.</li>
</ul>
<p><strong>How to connect:</strong></p>
<ol>
<li><a href="https://docs.ludus.cloud/docs/quick-start/using-cli-locally#wireguard">Generate your config</a>: ludus user wireguard &gt; ludus.conf  </li>
<li>Import this into your local WireGuard client and activate the tunnel.  </li>
<li>Connect directly to the private IPs of your VMs (e.g., 10.10.10.11) over the tunnel.</li>
</ol>
<h2 id="phase2executingtheattacks"><strong>Phase 2: Executing the Attacks</strong></h2>
<p>With the high-fidelity, fully instrumented range deployed, the "Red Team" phase can begin. This involves logging into a dedicated attacker VM (like the included Kali VM or a remnux-analyzer VM) and executing the attacks. This activity generates the rich, malicious telemetry that Elastic Defend will capture.</p>
<p>This combined range allows for testing defenses against the two dominant, macro-level threat vectors: identity-based "living-off-the-land" (LotL) attacks and vulnerability-based supply-chain intrusions.</p>
<h3 id="51activedirectorysimulationgoad"><strong>5.1 Active Directory Simulation (GOAD)</strong></h3>
<ul>
<li><strong>Initial Access</strong> (Credential Stuffing)  </li>
</ul>
<ol>
<li>The attacker targets the external perimeter. Using a list of breached credentials, you execute a password stuffing attack against the Essos.local domain. You successfully validate the credentials for the user khal.drogo.  </li>
<li>Sample Tool: kerbrute or smartbrute  </li>
<li>Result: Valid credentials for a low-privilege domain user.  </li>
</ol>
<ul>
<li><strong>Privilege Escalation</strong> (PrintNightmare)  </li>
</ul>
<ol>
<li>khal.drogo has limited rights. To gain a foothold on the CastelBlack server, you exploit PrintNightmare (CVE-2021-34527). This vulnerability in the Windows Print Spooler service allows any authenticated user to install a malicious print driver. You upload a driver that adds a new local admin user to the box.  </li>
<li>Sample Tool: CVE-2021-34527.py exploit script  </li>
<li>Result: Local SYSTEM access on CastelBlack.  </li>
</ol>
<ul>
<li><strong>Credential Dump</strong> (DCSync Preparation)  </li>
</ul>
<ol>
<li>Now running as SYSTEM/Admin on CastelBlack, you inspect the machine for cached credentials. You run Impacket's secretsdump to pull hashes from the SAM database and LSASS memory. You discover the NTLM hash for the built-in Administrator account, which was left in memory from a previous support session.  </li>
<li>Sample Tool: impacket-secretsdump  </li>
<li>Result: NTLM Hash of a Domain Admin or high-privilege account.  </li>
</ol>
<ul>
<li><strong>Kerberoasting</strong>  </li>
</ul>
<ol>
<li>With valid domain credentials, you pivot to the internal network. You request Kerberos Service Tickets (TGS) for Service Principal Names (SPNs) in the environment. You target the MSSQLSvc account. You take the encrypted ticket offline and crack it to reveal the plaintext password for the SQL service account.  </li>
<li>Sample Tool: Rubeus or GetUserSPNs.py  </li>
<li>Result: Plaintext password for the MSSQL service account.  </li>
</ol>
<ul>
<li><strong>MSSQL Attacks</strong>  </li>
</ul>
<ol>
<li>You use the cracked SQL credentials to authenticate directly to the Braavos SQL Server. Since the service account has sysadmin rights, you abuse the xp_cmdshell stored procedure. This feature allows you to spawn a Windows command shell directly from a SQL query, effectively giving you Remote Code Execution (RCE) on the database server.  </li>
<li>Sample Tool: mssqlclient.py  </li>
<li>Result: RCE on the Database Server.  </li>
</ol>
<ul>
<li><strong>Persistence</strong> (Scheduled Task)  </li>
</ul>
<ol>
<li>To ensure you don't lose access if the SQL password changes, you establish persistence. You create a Windows Scheduled Task on the compromised SQL server. This task is configured to execute a beacon binary every day, running as SYSTEM.  </li>
<li>Sample Tool: schtasks.exe or PowerShell  </li>
<li>Result: Long-term persistence.</li>
</ol>
<h3 id="52malwarelabsimulationxzbot"><strong>5.2 Malware Lab Simulation (XZbot)</strong></h3>
<ul>
<li>Step 7: Supply Chain Pivot (XZ Backdoor)  </li>
<li>Simultaneously, you target the Linux infrastructure in the DMZ. You trigger the pre-implanted XZ Backdoor (CVE-2024-3094) on the xz-backdoor-dect VM. By manipulating the SSH handshake with a specific cryptographic key, you bypass authentication entirely and execute commands as root without leaving standard SSH logs.  </li>
<li>Tool: xzbot  </li>
<li>Result: Root access on Linux infrastructure via supply chain compromise.  </li>
<li>The attacker uses the xzbot client provided in the Ludus lab.  </li>
<li>From the attacker VM, the following command is run to trigger the backdoor on the vulnerable Debian host:<br />
xzbot --ssh-addr '10.X.X.X:22' -cmd 'setsid sh -c "echo test"' 2&gt;&amp;1  </li>
<li>This action causes the sshd process on the target to anomalously spawn a shell and execute the command as root, creating definitive proof of execution.</li>
</ul>
<h2 id="phase3unifieddetectioninvestigationwithelasticsecurity"><strong>Phase 3: Unified Detection &amp; Investigation with Elastic Security</strong></h2>
<p>This is the "Blue Team" payoff. The telemetry and alerts generated in Phase 2 are now available for analysis within the unified Elastic Security platform.</p>
<h3 id="61thepowerfulsiemcentralizedvisibilityprebuiltdetections"><strong>6.1 The "Powerful SIEM": Centralized Visibility &amp; Prebuilt Detections</strong></h3>
<p>The power of the Elastic SIEM is not just in its ability to passively collect logs. Its power comes from the <em>active analysis</em> it performs on the deep, contextual data provided by Elastic Defend. The "Complete Endpoint Visibility" from Defend provides not just basic logs, but kernel-level telemetry - process creations, file modifications, network connections, and registry changes.</p>
<p>This rich data, all normalized to the Elastic Common Schema (ECS), feeds Elastic's extensive library of <strong>~1500+ prebuilt, MITRE-mapped detection rules</strong>. These rules are researched, developed, and maintained by the Elastic Security Labs team, providing out-of-the-box detection value.</p>
<p>The Ludus range serves as the perfect validation platform for this value. The attacks executed in Phase 2 are not theoretical; they are mapped directly to specific expected artifacts ("smoking gun"). A combination of prebuilt rules and custom rules is intentionally used together in the example to alert on specific behaviors.</p>
<p>| Attack Step | MITRE ATT&amp;CK | Elastic Detection Rule | Expected Artifact ("smoking gun") |
| :---- | :---- | :---- | :---- |
| <strong>1. Credential Stuffing</strong> | T1110 (Brute Force) | <strong>Potential Account Brute Force (Custom)</strong> | Abnormal Auth Success (Event 4624 and ssh login) across hosts. |
| <strong>2. PrintNightmare</strong> | T1068 (Exploitation) | <strong>Unusual Print Spooler Child Process</strong> | Unusual Print Spooler service (spoolsv.exe) child processes. |
| <strong>3. Credential Dump</strong> | T1003.006 (OS Credential Dumping) | <strong>Potential Remote Credential Access via Registry</strong> | Abnormal access to the Security Account Manager (SAM) registry hive. |
| <strong>4. Kerberoasting</strong> | T1558.003 (Kerberoasting) | <strong>Suspicious Kerberos Authentication Ticket Request (Custom)</strong> | Event ID 4769 with 0x17 (RC4) encryption requested. |
| <strong>5. MSSQL Attacks</strong> | T1505.001 (SQL Stored Procedures) | <strong>Execution via MSSQL xp_cmdshell Stored Procedure</strong> | Execution via MSSQL xp_cmdshell stored procedure |
| <strong>6. Persistence</strong> | T1053.005 (Scheduled Task) | <strong>A scheduled task was created</strong> | Event ID 4698 or schtasks.exe /create. |
| <strong>7. XZ Backdoor</strong> | T1210 (Exploitation of Remote Services) | <strong>Potential Execution via SSH Backdoor</strong> | sshd spawns unusual child processes like sh or bash. |</p>
<p><em>Note: Elastic detection rules are open and transparent. You can view the logic, contribute, or raise issues directly on the(<a href="https://github.com/elastic/detection-rules">https://github.com/elastic/detection-rules</a>).</em></p>
<h3 id="62deepdivetracingprocesschainswitheventanalyzer"><strong>6.2 Deep Dive: Tracing Process Chains with Event Analyzer</strong></h3>
<p>The two labs (GOAD and XZbot) provide a perfect opportunity to use Elastic's specialized investigation tools. The user interface of the Event Analyzer is designed to abstract the complexity of JSON logs into a cognitive model that aligns with how security analysts think: <strong>Process Chains.</strong> The interface is comprised of three primary interaction zones: the Graphical Canvas, the Detail Panel, and the Timeline integration.</p>
<h4 id="whatareweseeing">What are we seeing?</h4>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8bc908cfcaf654eb/6a7d7dc7b4377035d54d3ed4/image1.png" alt="" /></p>
<h4> </h4>
<h5 id="thegraphicalcanvastheprocesstree">The Graphical Canvas (The Process Tree)</h5>
<p>The central view is a directed acyclic graph where:</p>
<ul>
<li><strong>Nodes (Cubes):</strong> Each cube represents a distinct process execution. The visualization distinguishes between the "Anchor" event (highlighted with a blue halo) and the surrounding context.  </li>
<li><strong>Edges (Lines):</strong> Lines represent the parent-child relationship. The directionality is implicit (top-down or left-right), showing the flow of execution.  </li>
<li><strong>Visual Badging:</strong> Nodes are not static icons; they are dynamic indicators.  </li>
<li><strong>Alert Badges:</strong> If a specific process triggered a detection rule (e.g., "Malware Detected"), a colored badge appears on the cube. This allows an analyst to instantly identify which step in the chain was flagged by the detection engine.  </li>
<li><strong>User Context:</strong> Visual cues may indicate if a process changed user context (e.g., from a local user to SYSTEM), signaling privilege escalation.</li>
</ul>
<h5 id="thedetailpanelforensicmetadata">The Detail Panel (Forensic Metadata)</h5>
<p>Clicking on any node triggers the Detail Panel, typically sliding in from the right. This panel is the primary source of "What you can see" at a granular level. It exposes fields critical for verification:</p>
<ul>
<li><strong>Command Line Arguments:</strong> This is arguably the single most valuable forensic artifact. The Analyzer displays the full string, exposing flags, scripts, and encoded payloads (e.g., powershell.exe -w hidden -enc Base64).  </li>
<li><strong>Process Path and Hash:</strong> The full file path helps identify masquerading (e.g., svchost.exe running from C\:Temp instead of C:\Windows\System32). File hashes (MD5, SHA-1, SHA-256) are presented for cross-referencing with threat intelligence.  </li>
<li><strong>Signer Information:</strong> Information about the binary's digital signature helps distinguish between trusted Microsoft binaries and unsigned malware.  </li>
<li><strong>Related Event Counts:</strong> Instead of cluttering the graph with thousands of file modifications, the node displays summary statistics (e.g., "15 File Events," "3 Network Connections"). Clicking these stats usually drills down into a list view or timeline of those specific actions.</li>
</ul>
<h5 id="thetemporaldimensiontimefilter">The Temporal Dimension (Time Filter)</h5>
<p>A critical, often overlooked aspect of the Analyzer is its handling of time. Attacks can have long "dwell times." A parent process might have started weeks ago (e.g., a legitimate service), while the malicious child spawned today. The Analyzer includes a time slider that allows the analyst to expand the query window. By default, it might look at a narrow window around the alert, but expanding this allows the graph to "reach back" into the Warm or Cold data tiers to find the long-running parent process.</p>
<h4 id="howdoesitwork">How does it work?</h4>
<p>The operational capability of the Event Analyzer leverage the <strong>Elastic Common Schema (ECS)</strong>. In a heterogeneous security environment, logs originate from diverse sources—Windows endpoints, Linux servers, network firewalls, and cloud service providers—each with a unique taxonomy. A CrowdStrike agent might label a process ID as TargetProcessId, while a Sysmon event uses ProcessId. Without normalization, correlating these events into a single chain is algorithmically impossible.<br />
ECS solves this by enforcing a strict field hierarchy. The Event Analyzer relies on specific, high-fidelity ECS fields to construct the visual graph:</p>
<ul>
<li><strong>process.entity_id</strong>: This is the cornerstone of the Analyzer's logic. Operating systems recycle Process IDs (PIDs). A PID of 1234 might belong to svchost.exe at 09:00 and malware.exe at 14:00. Relying on PID for long-term historical analysis introduces collisions that would corrupt the visual graph, linking unrelated events. The process.entity_id is a unique string generated by the Elastic Agent (or ECS-compliant beats) that persists uniquely in the index, ensuring that the graph represents a distinct execution instance, regardless of PID reuse.  </li>
<li><strong>process.parent.entity_id</strong>: This field establishes the directed edge between nodes. By recursively querying for events where the process.entity_id of one event matches the process.parent.entity_id of another, the Analyzer reconstructs the lineage.</li>
</ul>
<p><strong>event.sequence</strong>: In high-velocity environments, the order of events (e.g., did the file modification happen before or after the network connection?) is critical. ECS timestamps and sequence numbers allow the Analyzer to order events chronologically within the visual node details.</p>
<h3 id="63deepdivereconstructinguseractivitywithsessionviewer"><strong>6.3 Deep Dive: Reconstructing User Activity with Session Viewer</strong></h3>
<p>For the <strong>XZbot</strong> (Linux) attack, the <strong>Session Viewer</strong> is the superior tool. It is specifically designed for <strong>"monitoring and investigating session activity on Linux infrastructure"</strong>.</p>
<p>When the Potential Execution via XZBackdoor alert fires, the analyst investigates the associated sshd process. The Session Viewer presents a <strong>"highly readable format inspired by the terminal"</strong>. It reconstructs the attacker's session, showing the sshd process and its anomalous child process (sh).</p>
<p>Furthermore, it will show the <em>exact command</em> that was executed (<code>sh -c setsid sh -c "usermod -aG sudo sysadmin_backup"</code>) and can even display the <em>output</em> of that command. This is the definitive "smoking gun", presented to the analyst in plain, human-readable text, effectively allowing them to watch the attacker's TTY session after the fact.</p>
<h4 id="whatareweseeing-1">What are we seeing?</h4>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4b26b82a6b5aff69/6a7d7dca448e4e06595bda9d/image2.png" alt="" /></p>
<p>The user interface of the Session Viewer is explicitly designed to bridge the gap between abstract log analysis and the native terminal experience of a Linux administrator. Unlike the Event Analyzer, which focuses on malware process chains, the Session Viewer presents a time-ordered, tree-based visualization that reconstructs the linear narrative of a shell session.</p>
<h5 id="theprocesstreeandtimeline">The Process Tree and Timeline</h5>
<p>The central component of the view is a <strong>Directed Acyclic Graph (DAG)</strong> displayed as a hierarchical list.</p>
<ul>
<li><strong>Vertical Flow:</strong> The Session Viewer arranges processes vertically, mimicking the flow of a terminal history file but preserving hierarchy. Child processes are indented relative to their parents. This allows an analyst to immediately distinguish between a command run directly by the user (e.g., curl) and a process spawned by a script execution (e.g., curl executing inside a setup.sh script).  </li>
<li><strong>Verbose Mode:</strong> A toggle allows analysts to switch between a filtered view (showing significant user activity) and "Verbose Mode." When enabled, this mode reveals typically noisy events like shell startup scripts (.bashrc execution), shell completion helpers, and forks caused by built-in commands. This is crucial for detecting persistence mechanisms hidden in profile scripts.</li>
</ul>
<h5 id="visualbadgingandindicators">Visual Badging and Indicators</h5>
<p>The UI employs a sophisticated system of badges and icons to provide immediate context without requiring the analyst to drill down into every node. These visual cues are essential for rapid triage.</p>
<h6 id="visualindicatorsinelasticsessionviewer"><em>Visual Indicators in Elastic Session Viewer</em></h6>
<p>| Badge/Icon | Visual Appearance | Meaning | Forensic Implication |
| :---- | :---- | :---- | :---- |
| <strong>Exec User Change</strong> | Explicit Text Badge | The user context changed (e.g., su, sudo). | Critical for identifying privilege escalation. Shows exactly when a standard user became root. |
| <strong>Process Alert</strong> | Gear Icon | A process event triggered a detection rule. | Indicates execution of malicious binaries or suspicious arguments (e.g., whoami). |
| <strong>File Alert</strong> | Page Icon | A file modification triggered a rule. | Indicates tampering, persistence creation (cron/systemd), or exfiltration staging. |
| <strong>Network Alert</strong> | Page Icon (Secondary) | A network event triggered a rule. | Indicates C2 communication, lateral movement, or exfiltration. |
| <strong>Multiple Alerts</strong> | Combined Badge | Single event triggered multiple rule types. | High-confidence indicator of malicious activity (e.g., a process dropped a file and executed it). |
| <strong>Alert Count</strong> | Numeric (e.g., (2)) | Total alerts associated with a node. | Helps prioritize which steps in the chain were most "noisy" to detection logic. |</p>
<h5 id="terminaloutputview">Terminal Output View</h5>
<p>Hovering over the <strong>Terminal Output</strong> button on a process node reveals a badge indicating the size of the captured output. Clicking this button opens the Terminal Output view, which renders the process.io.text data. This is the "Smoking Gun" feature for Linux investigations.</p>
<ul>
<li><strong>Replay Capability:</strong> It allows the analyst to see exactly what the user saw. If an attacker ran cat /etc/passwd, the process tree shows the execution; the Terminal Output view shows the <em>content</em> of the passwd file as it was displayed to the attacker.  </li>
<li><strong>Input Reconstruction:</strong> Because the viewer captures TTY I/O, it captures not just the command execution, but the <em>typing</em>. This can reveal backspaces, typos, and corrections (e.g., typing sdo [backspace] sudo), which are strong behavioral indicators of a human adversary rather than an automated script.</li>
</ul>
<h2 id="theelasticadvantageaipoweredautomatedhunting"><strong>The Elastic Advantage: AI-Powered Automated Hunting</strong></h2>
<p>The process described in Phase 3 demonstrates a powerful, analyst-driven investigation. However, the primary advantage of using <strong>Elastic Cloud Hosted (ECH)</strong> or <strong>Elastic Serverless</strong> is the programmatic access to an integrated Generative AI stack. This stack elevates the process from <em>manual correlation</em> to <em>AI-driven automated hunting</em>.</p>
<p><em>Note: Elastic's AI features work with the out-of-the-box Elastic Managed LLMs or with <a href="https://www.elastic.co/docs/solutions/security/ai/set-up-connectors-for-large-language-models-llm#connect-to-a-third-party-llm">third-party LLMs</a> configured using one of the available connectors.</em> </p>
<h3 id="71fromalertstoattacksautomatedcorrelationwithattackdiscovery"><strong>7.1 From Alerts to Attacks: Automated Correlation with Attack Discovery</strong></h3>
<p>The GOAD + XZbot labs will generate <em>multiple</em> discrete alerts, as shown in the table above. A junior analyst would be faced with a queue of alerts: Potential Kerberoasting, Suspicious Certificate Request, and Potential XZBackdoor and have to manually "stitch together" this complex, cross-domain attack.</p>
<p>This is the problem solved by <strong>Attack Discovery</strong>. This GenAI feature, available in Enterprise and Serverless tiers, <strong>"delivers fully automated threat hunting at scale"</strong>. It "AI analyzes every alert to uncover hidden threats", automatically correlating the disparate signals from the Ludus lab into a single, high-fidelity "Attack" investigation.</p>
<p>The primary value of Attack Discovery for a forensic analyst is the compression of time. It automates the "mental stitching" that defines tier-one and tier-two analysis.</p>
<h4 id="deconstructingthementalstitching">Deconstructing the "Mental Stitching"</h4>
<p>Consider an example investigation without Attack Discovery.</p>
<ol>
<li><strong>Trigger:</strong> You see an alert: "Suspicious PowerShell Execution."  </li>
<li><strong>Query:</strong> You pivot to the host timeline.  </li>
<li><strong>Scan:</strong> You scroll back 15 minutes. You see a "File Download" event.  </li>
<li><strong>Hypothesis:</strong> "Maybe the user downloaded a bad file, which launched PowerShell."  </li>
<li><strong>Verification:</strong> You check the file name. It is invoice.js.  </li>
<li><strong>Conclusion:</strong> "Confirmed malware download."</li>
</ol>
<p>This process takes between 10 and 30 minutes, dependingon the analyst's skill and familiarity with the environment. Attack Discovery performs this entire sequence in seconds. It looks at the PowerShell alert, sees the file download event in the related context, and presents a Discovery stating: <em>"User executed suspicious PowerShell script likely originating from downloaded file 'invoice.js'."</em></p>
<p>This feature includes <strong>Data Persistence</strong> (results are saved for historical tracking) and <strong>Scheduling &amp; Actions</strong> (it runs automatically and can trigger responses or subsequent Elastic Workflows), moving the SOC from a reactive to a proactive posture. </p>
<h5 id="example">Example</h5>
<p>In our example, as the Attack occurs, we start to see alerts. Instead of triaging the alerts individually, we leverage Attack Discovery for triage.<br />
Compressing the mean-time-to-triage down to seconds and quickly identifying the 2 attacks.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf3ef203844e4cb9a/6a7d7dcf73d9bd4ea129ab4b/image3.gif" alt="" /></p>
<h3 id="72acceleratingtriagewiththeaiassistant"><strong>7.2 Accelerating Triage with the AI Assistant</strong></h3>
<p>The Elastic Security Assistant uses generative AI to help you find, fix and understand security threats. It works directly inside Elastic Security. You interact with it through a chat interface to investigate alerts and write code.</p>
<p>In our example, once Attack Discovery identifies a correlated attack, we then use the <strong>AI Assistant</strong> to investigate. The assistant provides two key capabilities:</p>
<ol>
<li><strong>Natural Language Investigations:</strong> The analyst can ask plain-English questions like, "Summarize this attack", "What is the MITRE Tactic for this process?", "What is print spooler?" or “Provide some remediation suggestions.”  </li>
</ol>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt800c9fa8feaf80ac/6a7d7dd22f00b2e270efbe30/image7.png" alt="" /></p>
<ol>
<li><strong>Agentic Query Validation workflow:</strong> This advanced feature allows the AI to <strong>"generate bespoke, validated ES|QL queries"</strong>. An analyst can ask, "Find all network connections from the host involved in the XZbot alert", and the assistant will write, validate, and <strong>self-correct</strong> the query before presenting it, drastically lowering the skill barrier to high-end threat hunting.<br />
<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc1522253e85b774d/6a7d7dd573d9bd3dc329ab4f/image4.png" alt="" /></li>
</ol>
<h4 id="howitworks">How It Works</h4>
<p>The Assistant connects your Elastic Stack to an LLM of your choice (e.g., GPT-5, Claude, Gemini). It uses Retrieval Augmented Generation (RAG) to fetch relevant data—logs, alerts, and internal documentation—from your environment. You can configure it to anonymize sensitive fields (PII or host/IP metadata) before sending the prompt to the model, ensuring your data remains private while the model reasons the behavioral patterns.</p>
<h3 id="73intelligentautomationwithelasticworkflows"><strong>7.3 Intelligent Automation with Elastic Workflows</strong></h3>
<p>The attacks described above generate complex, multi-stage alerts. Handling these manually is slow. Elastic has addressed this by acquiring <a href="https://www.elastic.co/blog/elastic-and-keep-join-forces"><strong>Keep</strong></a>, an open-source AIOps and alert management platform. In <a href="https://www.elastic.co/blog/whats-new-elastic-9-3-0">Elastic 9.3</a>, this technology is integrated directly into Kibana in Technical Preview as <a href="https://www.elastic.co/docs/explore-analyze/workflows">Elastic <strong>Workflows</strong></a>.</p>
<h4 id="whatareworkflows">What are Workflows?</h4>
<p>Elastic Workflows is an automation engine built into the Elasticsearch platform. You define Workflows in YAML - what triggers them, what steps they take, what actions they perform - and the platform handles execution. A Workflow can query your environment, transform and enrich security data, branch based on conditions, call external APIs, and integrate with services like Slack, Jira, PagerDuty and more through connectors you've already configured. Workflows can also call AI agents to reason through complex investigations, then continue with response actions based on what the agent discovers. Elastic Workflows combines scripted automation with AI reasoning natively in your SIEM, where your security data already lives.</p>
<h4 id="howitworksthealertaggregatorworkflowengine">How It Works: The "Alert Aggregator &amp; Workflow Engine"</h4>
<p>Workflows become the <strong>middleware layer</strong> between detection and remediation, working through three primary mechanisms:</p>
<ul>
<li><strong>Multi-Source Ingestion:</strong> Workflows extend beyond Elastic. Pulling in additional data for enrichment, analysis or initial triage.  </li>
<li><strong>Workflow-as-Code (YAML):</strong> Workflows are defined in YAML files. This allows teams to version control their incident response procedures as code.  </li>
<li><strong>The Workflow Engine:</strong> When an alert triggers in Elastic (or an external tool), the Workflow Engine executes a series of steps:  </li>
</ul>
<ol>
<li><strong>Enrichment:</strong> Querying an API (like VirusTotal or Active Directory) to add context.  </li>
<li><strong>Logic:</strong> Using if/else statements to determine severity.  </li>
<li><strong>Action:</strong> Sending a Slack message, creating a Jira ticket, or triggering an Elastic Defend response action.</li>
</ol>
<p><strong>Consider an example Alert and Action flow.</strong></p>
<ul>
<li><strong>Trigger:</strong> You connect the workflow to a specific rule, such as "Malicious Detection Alert".  </li>
<li><strong>Steps:</strong> You define a sequence of actions.  </li>
</ul>
<ol>
<li><strong>Triage (Agentic):</strong> Pass the alert to the AI Assistant. Ask the questions: "How would we remediate and respond to the alert below?”  </li>
<li><strong>Enrich</strong>: Attach the AI Assistant's response as a note to the alert.   </li>
<li><strong>Respond:</strong> Create a case with a link to the alert note.</li>
</ol>
<h5 id="example-1">Example</h5>
<p>In our example, we have alerts that trigger our Workflow - Alert Enrichment &amp; Case Creation.<br />
We will also directly trigger it from the Workflows UI to demonstrate the various steps. </p>
<ul>
<li>The Alert context is provided as an input to the Security AI Assistant  </li>
<li>The response is added as a note to the Security alerts  </li>
<li>A case is created with metadata from the Alert (timestamp, severity, rule name and alert reason).   </li>
<li>A link to the case is added to the case as a comment. <em>Note: this is not shown in the GIF</em>.</li>
</ul>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf24fc573f033d77d/6a7d7dd9de2315848cfd4d93/image6.gif" alt="" /></p>
<h2 id="conclusionfrommanualsetuptocontinuousemulation"><strong>Conclusion: From Manual Setup to Continuous Emulation</strong></h2>
<p>This blog has provided a complete blueprint for an advanced, scalable, and most importantly, a safe simulation range.</p>
<ol>
<li><strong>We built:</strong> A complex, multi-lab range (GOAD + XZbot) was deployed with a single command using Ludus.  </li>
<li><strong>We instrumented:</strong> The entire range was seamlessly instrumented with Elastic Agent and Defend as part of the automated deployment, using the ludus_elastic_agent Ansible role.  </li>
<li><strong>We secured:</strong> The critical conflict between malware isolation and cloud-agent connectivity was solved using Ludus's granular "OPSEC" networking controls.  </li>
<li><strong>We validated:</strong> The platform's powerful SIEM capabilities were proven by <em>validating</em> Elastic's prebuilt, out-of-the-box detection rules against live, known-bad attacks.  </li>
<li><strong>We investigated:</strong> The specialized investigation tools, Event Analyzer and Session Viewer, were used to trace the <em>exact</em> attack paths on both Windows and Linux hosts.  </li>
<li><strong>We automated:</strong> The "force-multiplier" of Elastic's GenAI stack was demonstrated, with Attack Discovery automatically correlating disparate alerts into a single attack and the AI Assistant accelerating the final investigation.  </li>
<li><strong>We responded</strong>: The power of Elastic Workflows provide the brains and automation for complex response actions and remediation flows.</li>
</ol>
<p>This architecture is not a one-off build. It is a blueprint for a <em>continuous detection engineering pipeline</em>. It "modernizes security operations" by empowering purple teams to tear down, rebuild, and re-test their defenses on demand, ensuring their detection posture evolves as fast as the threats do.</p>
<h2 id="takethenextstepenableyoursecurityteam"><strong>Take the Next Step: Enable Your Security Team</strong></h2>
<p>The architecture in this blog is more than a technical exercise; it's a blueprint for continuous security validation. By pairing this automated range with Elastic’s unified SIEM and XDR platform, you can move from periodic testing to a state of constant readiness.</p>
<p><a href="https://cloud.elastic.co/registration">We invite you to start your own trial</a>, leverage this guide to test and evaluate the platform against real-world threats, and enable your security team with the tools to stay one step ahead of the adversary.</p>
<h3 id="usinganothersiem">Using another SIEM?</h3>
<p>No problem. You can leverage Elastic Serverless and augment your existing SIEM, then gain all of the insights above while using your native SIEM's underlying data. <a href="https://cloud.elastic.co/registration">Get started with an Elastic Serverless deployment today</a>. The <a href="https://www.elastic.co/docs/solutions/security/ai/ease/ease-intro"><strong>Elastic AI SOC Engine (EASE)</strong> package</a> delivers these AI-driven capabilities, enabling organizations to rapidly add powerful analytics and an AI layer on top of their existing tools before the full migration.</p>
<h2 id="appendix">Appendix</h2>
<h3 id="examplefullrange">Example Full Range</h3>
<p><em>Note: The Kali VM VLAN is outside of the GOAD and XZ backdoor hosts to simulate a segmented network or a remote attacker. The Kali VM VLAN can be changed to 10/20 to simulate “assumed breach” or internal attack scenarios.</em> </p>
<pre><code>global_role_vars:
  ludus_elastic_fleet_server: "https://&lt;fleet_domain&gt;:&lt;fleet_port&gt;" #443 by default for cloud   ## Note on prem fleet server defaults to 8220
  ludus_elastic_agent_version: "9.2.1"
ludus:
  - vm_name: "{{ range_id }}-GOAD-DC01"
    hostname: "{{ range_id }}-DC01"
    template: win2019-server-x64-template
    vlan: 10
    ip_last_octet: 10
    ram_gb: 4
    cpus: 2
    windows:
      sysprep: true
    dns_rewrites:           # Any values in this array will be added to DNS for the range and return an A record for this VM's IP
      - sevenkingdoms.local
      - kingslanding.sevenkingdoms.local
      - kingslanding
    roles:
      - badsectorlabs.ludus_elastic_agent
    role_vars:
      ludus_elastic_enrollment_token: "&lt;goad_policy_enrollment_token&gt;"
  - vm_name: "{{ range_id }}-GOAD-DC02"
    hostname: "{{ range_id }}-DC02"
    template: win2019-server-x64-template
    vlan: 10
    ip_last_octet: 11
    ram_gb: 4
    cpus: 2
    windows:
      sysprep: true
    dns_rewrites:
      - winterfell.north.sevenkingdoms.local
      - north.sevenkingdoms.local
      - winterfell
    roles:
      - badsectorlabs.ludus_elastic_agent
    role_vars:
      ludus_elastic_enrollment_token: "&lt;goad_policy_enrollment_token&gt;"
  - vm_name: "{{ range_id }}-GOAD-DC03"
    hostname: "{{ range_id }}-DC03"
    template: win2016-server-x64-template
    vlan: 10
    ip_last_octet: 12
    ram_gb: 4
    cpus: 2
    windows:
      sysprep: true
    dns_rewrites:
      - essos.local
      - meereen.essos.local
      - meereen
    roles:
      - badsectorlabs.ludus_elastic_agent
    role_vars:
      ludus_elastic_enrollment_token: "&lt;goad_policy_enrollment_token&gt;"
  - vm_name: "{{ range_id }}-GOAD-SRV02"
    hostname: "{{ range_id }}-SRV02"
    template: win2019-server-x64-template
    vlan: 10
    ip_last_octet: 22
    ram_gb: 4
    cpus: 2
    windows:
      sysprep: true
    dns_rewrites:
      - castelblack.north.sevenkingdoms.local
      - castelblack
    roles:
      - badsectorlabs.ludus_elastic_agent
    role_vars:
      ludus_elastic_enrollment_token: "&lt;goad_policy_enrollment_token&gt;"
  - vm_name: "{{ range_id }}-GOAD-SRV03"
    hostname: "{{ range_id }}-SRV03"
    template: win2019-server-x64-template
    vlan: 10
    ip_last_octet: 23
    ram_gb: 4
    cpus: 2
    windows:
      sysprep: true
    dns_rewrites:
      - braavos.essos.local
      - braavos
    roles:
      - badsectorlabs.ludus_elastic_agent
    role_vars:
      ludus_elastic_enrollment_token: "&lt;your_enrollment&gt;"
  - vm_name: "{{ range_id }}-xz-backdoor-dect"
    hostname: "{{ range_id }}-xz-backdoor-dect"
    template: debian-12-x64-server-template
    vlan: 20
    ip_last_octet: 1
    ram_gb: 2
    cpus: 2
    linux:
      packages: # You can define packages to install on Linux hosts
        - ca-certificates
        - netcat-openbsd
        - net-tools
    roles:
      - badsectorlabs.ludus_xz_backdoor
      - badsectorlabs.ludus_elastic_agent
    role_vars:
      ludus_xz_backdoor_install_xzbot: true
      ludus_xz_backdoor_install_backdoor: true
      ludus_elastic_enrollment_token: "&lt;linux_policy_enrollment_token&gt;"
  - vm_name: "{{ range_id }}-kali"
    hostname: "{{ range_id }}-kali"
    template: kali-x64-desktop-template
    vlan: 50
    ip_last_octet: 99
    ram_gb: 8
    cpus: 4
    linux: true
    testing:
      snapshot: false # Snapshot this VM going into testing, and revert it coming out of testing. Default: true
      block_internet: false # Allow internet access for Kali, default is true
    roles:
      - badsectorlabs.ludus_xz_backdoor
      - badsectorlabs.ludus_elastic_agent
    role_vars:
      ludus_xz_backdoor_install_xzbot: true
      ludus_elastic_enrollment_token: "&lt;linux_policy_enrollment_token&gt;"
</code></pre>
<p><em>The release and timing of any features or functionality described in this post remain at Elastic's sole discretion. Any features or functionality not currently available may not be delivered on time or at all.</em></p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/automating-goad-and-live-malware-labs</link>
    <guid isPermaLink="false">automating-goad-and-live-malware-labs</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Nic Palmer,Adrian Chen]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd013cf9fe7adda36/6a7d7ddbe88c65f3cf0088ee/Security_Labs_Images_34.jpg" length="0" type="image/jpeg"/>
    <pubDate>Thu, 05 Feb 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[From Qradar to Elastic: Automate your Detection Rule Migration]]></title>
    <description><![CDATA[Today, we are excited to announce a major expansion to our Automatic Migration feature that changes that narrative. In Elastic Security 9.3, we are introducing Automatic Migration support for QRadar detection rules (now in Tech Preview), joining our existing Splunk translation capabilities to further expedite your journey to Elastic Security. Let's take a closer look at what's supported.]]></description>
    <content:encoded><![CDATA[<p>Migrating to a new SIEM is often viewed as a daunting task. The sheer volume of legacy detection rules, <a href="https://www.elastic.co/blog/automatic-migration-for-dashboards">dashboards</a>, and custom configurations can keep security teams locked into aging infrastructure simply because the cost of moving — measured in manual effort and time — is too high.</p>
<p>Today, we are excited to announce a major expansion to our Automatic Migration feature that changes that narrative. In Elastic Security 9.3, we are introducing Automatic Migration support for QRadar detection rules (now in Tech Preview), joining our existing Splunk translation capabilities to further expedite your journey to Elastic Security. Let's take a closer look at what's supported. </p>
<h2 id="whysiemmigrationischanging">Why SIEM Migration is Changing</h2>
<p>Traditionally, organizations had to manually rewrite every rule when switching platforms. This created a significant bottleneck where security coverage was either delayed or lost during the transition. With the latest updates to Automatic Migration, MSSPs and large organizations running multiple SIEMs can now translate both Splunk and QRadar rules into Elastic-native logic automatically. </p>
<h2 id="whatssupportedforautomaticmigrationforqradar">What’s Supported for Automatic Migration for QRadar</h2>
<p>The same <a href="https://www.elastic.co/blog/automatic-migration-ai-rule-translation">mapping and translation</a> is applied as prior rule types but now with support for XML exported QRadar rules. The following rule types are supported:</p>
<ul>
<li>Event - focus on log and event data.  </li>
<li>Flow - typically related to network detection scenarios.   </li>
<li>Common - a combination of event and flow rules</li>
</ul>
<p>We aren't just moving text; we are preserving the intelligence of your security operations. Reference sets are considered as part of the translation logic. We automatically put this information into lookup indexes where applicable. For more information on ES|QL lookup join syntax check out our <a href="https://www.elastic.co/docs/reference/query-languages/esql/esql-lookup-join">docs</a>. MITRE mappings are also preserved,so that upon rule install this is preserved in the migrated rule in elastic. Behind the scenes we take into account all building block rules as well. These building blocks help to contribute to the translation logic as seen in the summary tab for individual rules. </p>
<h2 id="streamliningtheonboardingprocess">Streamlining the onboarding process</h2>
<p>A common "chicken and egg" problem in SIEM migrations is whether to move data or rules first. Our framework provides flexibility for both:</p>
<ol>
<li>Rule-First Insight: You can translate rules before onboarding data. Elastic will identify which integrations are required for those rules to work, allowing you to prioritize your data onboarding.  </li>
<li>Data-First Traditionalism: If you prefer, you can onboard your log sources first and then migrate the rules to match.  </li>
<li>Custom Data: For unique sources, use <a href="https://www.elastic.co/docs/solutions/security/get-started/automatic-import">Automatic Import</a> to ingest custom data in minutes.</li>
</ol>
<p>By identifying exactly which integrations are needed before moving a single log, teams can build a precise, risk-aware roadmap for their migration project. This transparency eliminates the guesswork and helps ensure that critical visibility gaps are addressed long before you fully decommission your legacy environment.</p>
<h2 id="gettingstartedwithautomaticmigrationfordetectionrules">Getting started with Automatic Migration for Detection Rules</h2>
<p>To get started with Automatic Migration for Detection Rules, after deciding on migrating your detection rules and data, follow these three simple steps:</p>
<ol>
<li>Navigate to Elastic Security’s “Get started” page and configure your AI Provider. </li>
</ol>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt093a157550b866d1/6a7d80923ce8e29565cf2676/image1.png" alt="" /></p>
<ol>
<li>Select the drop down on the top right for QRadar. Let Elastic guide you through exporting your rules from QRadar and uploading them into Elastic Security. Elastic handles the finer details by scanning for reference sets, MITRE mappings, and then prompts you to upload them when found. MITRE mappings can only be included at the time of the initial translation so make sure to include them if you have this information.</li>
</ol>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta4e1f21cf986a9f2/6a7d80955967e53ac85da53c/image3.png" alt="" /></p>
<ol>
<li>Once the dashboards are uploaded, you can view their status. </li>
</ol>
<ul>
<li>Installed: Already added to Elastic SIEM. Click View to manage and enable it.  </li>
<li>Translated: Ready to install. This rule was mapped to an Elastic-authored rule, or translated by Automatic Import. Click Install to install it.  </li>
<li>Partially translated: Part of the query could not be translated. You may need to specify an index pattern for the rule query, upload missing files, or fix broken rule syntax.  </li>
<li>Not translated: None of the original query could be translated.  </li>
<li>Failed: Translation failed. Refer to the error for details.</li>
</ul>
<p>For more information, refer to the <a href="https://www.elastic.co/docs/solutions/security/get-started/automatic-migration">technical documentation</a>.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt752b0f5115769104/6a7d8098bd21980a8b7552b9/image2.png" alt="" /></p>
<ol>
<li>After clicking View Rules you will have the ability to edit and install rules. </li>
</ol>
<h2 id="howelasticsaifeaturesaidsocteams"><strong>How Elastic’s AI features aid SOC teams</strong></h2>
<p>Elastic Security brings generative AI into the SOC with <a href="https://www.elastic.co/docs/solutions/search/rag">retrieval augmented generation (RAG)</a> and open agentic frameworks. Automatic Migration joins the lineup of Elastic Security’s powerful AI features helping SOC teams strengthen defenses across the IT environment:</p>
<ul>
<li><a href="https://www.elastic.co/docs/solutions/security/get-started/automatic-migration">Automatic Migration for Detection Rules</a> complements Elastic’s deep library of prebuilt rules to broaden detection use case coverage.  </li>
<li><a href="https://www.elastic.co/blog/automatic-import-ai-data-integration-builder">Automatic Import</a> extends visibility <em>and powers detection rules</em> by onboarding custom data sources in minutes.  </li>
<li><a href="https://www.elastic.co/security-labs/ai-driven-security-analytics">Attack Discovery</a> distills the alerts generated by detection rules to pinpoint advancing threats and suggest next steps.  </li>
<li><a href="https://www.elastic.co/blog/introducing-elastic-ai-assistant">Elastic AI Assistant</a> guides analysts through investigation and response using natural language.</li>
</ul>
<p>Elastic’s Next Gen SIEM and XDR solution helps analysts detect earlier and respond faster.</p>
<h2 id="migratetoelasticsecuritytoday">Migrate to Elastic Security today</h2>
<p>The days of being stuck with a legacy SIEM are over. Whether you are migrating from Splunk or QRadar, Elastic is here to ensure your transition is fast, accurate, and powerful. Interested in testing Elastic Security first? <a href="https://www.elastic.co/cloud/cloud-trial-overview">Try it free</a>, or <a href="https://www.elastic.co/splunk-interest?elektra=organic&amp;storm=CLP&amp;rogue=splunkobs-gic">get in touch</a>.</p>
<p>Have feedback? Tell us what you think in the <a href="https://ela.st/slack">Elastic Community Slack channel</a> or on the <a href="https://discuss.elastic.co/c/security/83">Elastic Security forum</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/from-qradar-to-elastic</link>
    <guid isPermaLink="false">from-qradar-to-elastic</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Charles Davidson]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1828c53d235eeadd/6a7d809b3cab1ce10c0e19fa/Security_Labs_Images_10.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 03 Feb 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Elastic and Keep join forces to help users manage alerts and automate workflows]]></title>
    <description><![CDATA[Elastic announces the acquisition of Keep Alerting]]></description>
    <content:encoded><![CDATA[<p>We are thrilled to announce today that Elastic has entered into an agreement to acquire Keep Alerting Ltd (“Keep”), an open source AIOps company. The company unifies alerts behind a single pane of glass and dedupes, correlates, and prioritizes events to reduce noise and automate root cause analysis. Additionally, its workflow engine automates the remediation of incidents with workflow-as-code and a no-code visual interface.</p>
<p>“We’re excited to join Elastic and bring Keep’s capabilities to Elastic users,” said Tal Borenstein, founder and CEO of Keep. “As open source companies, we think there are natural synergies between Keep and Elastic, our products, and our communities.”</p>
<p>Keep is currently available as open source, enterprise software, and as a cloud service. Headquartered in Tel Aviv, Israel, the company’s products are used by SREs, engineers, and operations teams worldwide.</p>
<p>Going forward, Keep will integrate with Elasticsearch and Kibana and remain open source. Context from across the Keep tech stack (alerts, incidents, service topology, change management, playbooks) will benefit from the speed and scale of Elasticsearch. Meanwhile, Elastic users will benefit from the world-class AIOps and workflow automation capabilities that Keep brings to the Elastic Stack. Customers of our Observability, Security, and Search solutions will all benefit from greater AI-powered automation, enabled by Keep.</p>
<p>I’m delighted to welcome the Keep team to join us on our journey to help our users accelerate business outcomes through Search AI, and we look forward to sharing further updates on our plans.</p>
<p><strong>Disclaimer</strong></p>
<p>The release and timing of any features or functionality described in this document remain at Elastic's sole discretion. Any features or functionality not currently available may not be delivered on time or at all.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/elastic-and-keep-join-forces</link>
    <guid isPermaLink="false">elastic-and-keep-join-forces</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Ken Exner]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltea7194d70cad11f7/6a7d7f5cead8ec9e8dba7add/image1.png" length="0" type="image/png"/>
    <pubDate>Wed, 07 May 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[WinVisor – A hypervisor-based emulator for Windows x64 user-mode executables]]></title>
    <description><![CDATA[WinVisor is a hypervisor-based emulator for Windows x64 user-mode executables that leverages the Windows Hypervisor Platform API to provide a virtualized environment for logging syscalls and enabling memory introspection.]]></description>
    <content:encoded><![CDATA[<h2 id="background">Background</h2>
<p>In Windows 10 (version RS4), Microsoft introduced the <a href="https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/hypervisor-platform">Windows Hypervisor Platform</a> (WHP) API. This API exposes Microsoft's built-in hypervisor functionality to user-mode Windows applications. In 2024, the author used this API to create a personal project: a 16-bit MS-DOS emulator called <a href="https://github.com/x86matthew/DOSVisor">DOSVisor</a>. As mentioned in the release notes, there have always been plans to take this concept further and use it to emulate Windows applications. Elastic provides a research week (ON Week) twice per year for staff to work on personal projects, providing a great opportunity to begin working on this project. This project will be (unimaginatively) named WinVisor, inspired by its DOSVisor predecessor.</p>
<p>Hypervisors provide hardware-level virtualization, eliminating the need to emulate the CPU via software. This ensures that instructions are executed exactly as they would be on a physical CPU, whereas software-based emulators often behave inconsistently in edge cases.</p>
<p>This project aims to build a virtual environment for executing Windows x64 binaries, allowing syscalls to be logged (or hooked) and enabling memory introspection. The goal of this project is not to build a comprehensive and secure sandbox - by default, all syscalls will simply be logged and forwarded directly to the host. In its initial form, it will be trivial for code running within the virtualized guest to "escape" to the host. Safely securing a sandbox is a difficult task, and is beyond the scope of this project. The limitations will be described in further detail at the end of the article.</p>
<p>Despite having been available for 6 years (at the time of writing), it seems that the WHP API hasn’t been used in many public projects other than complex codebases such as <a href="https://github.com/qemu/qemu">QEMU</a> and <a href="https://www.virtualbox.org/">VirtualBox</a>. One other notable project is Alex Ionescu's <a href="https://github.com/ionescu007/Simpleator">Simpleator</a> - a lightweight Windows user-mode emulator that also utilizes the WHP API. This project has many of the same goals as WinVisor, although the approach for implementation is quite different. The WinVisor project aims to automate as much as possible and support simple executables (e.g. <code>ping.exe</code>) universally out of the box.</p>
<p>This article will cover the general design of the project, some of the issues that were encountered, and how they were worked through. Some features will be limited due to development time constraints, but the final product will at least be a usable proof-of-concept. Links to the source code and binaries hosted on GitHub will be provided at the end of the article.</p>
<h3 id="hypervisorbasics">Hypervisor basics</h3>
<p>Hypervisors are powered by VT-x (Intel) and AMD-V (AMD) extensions. These hardware-assisted frameworks enable virtualization by allowing one or more virtual machines to run on a single physical CPU. These extensions use different instruction sets and, therefore, are not inherently compatible with each other; separate code must be written for each.</p>
<p>Internally, Hyper-V uses <code>hvix64.exe</code> for Intel support and <code>hvax64.exe</code> for AMD support. Microsoft's WHP API abstracts these hardware differences, allowing applications to create and manage virtual partitions regardless of the underlying CPU type. For simplicity, the following explanation will focus solely on VT-x.</p>
<p>VT-x adds an additional set of instructions known as VMX (Virtual Machine Extensions), containing instructions such as <code>VMLAUNCH</code>, which begins the execution of a VM for the first time, and <code>VMRESUME</code>, which re-enters the VM after a VM exit. A VM exit occurs when certain conditions are triggered by the guest, such as specific instructions, I/O port access, page faults, and other exceptions. </p>
<p>Central to VMX is the Virtual Machine Control Structure (VMCS), a per-VM data structure that stores the state of the guest and host contexts as well as information about the execution environment. The VMCS contains fields that define processor state, control configurations, and optional conditions that trigger transitions from the guest back to the host. VMCS fields can be read or written to using the <code>VMREAD</code> and <code>VMWRITE</code> instructions.</p>
<p>During a VM exit, the processor saves the guest state in the VMCS and transitions back to the host state for hypervisor intervention.</p>
<h2 id="winvisoroverview">WinVisor overview</h2>
<p>This project takes advantage of the high-level nature of the WHP API. The API exposes hypervisor functionality to user-mode and allows applications to map virtual memory from the host process directly into the guest's physical memory.</p>
<p>The virtual CPU operates almost exclusively in CPL3 (user-mode), except for a small bootloader that runs at CPL0 (kernel-mode) to initialize the CPU state before execution. This will be described in further detail in the Virtual CPU section.</p>
<p>Building up the memory space for an emulated guest environment involves mapping the target executable and all DLL dependencies, followed by populating other internal data structures such as the Process Environment Block (PEB), Thread Environment Block (TEB), <code>KUSER_SHARED_DATA</code>, etc.</p>
<p>Mapping the EXE and DLL dependencies is straightforward, but accurately maintaining internal structures, such as the PEB, is a more complex task. These structures are large, mostly undocumented, and their contents can vary between Windows versions. It would be relatively simple to populate a minimalist set of fields to execute a simple "Hello World" application, but an improved approach should be taken to provide good compatibility.</p>
<p>Instead of manually building up a virtual environment, WinVisor launches a suspended instance of the target process and clones the entire address space into the guest. The Import Address Table (IAT) and Thread Local Storage (TLS) data directories are temporarily removed from the PE headers in memory to stop DLL dependencies from loading and to prevent TLS callbacks from executing before reaching the entry point. The process is then resumed, allowing the usual process initialization to continue (<code>LdrpInitializeProcess</code>) until it reaches the entry point of the target executable, at which point the hypervisor launches and takes control. This essentially means that Windows has done all of the hard work for us, and we now have a pre-populated user-mode address space for the target executable that is ready for execution.</p>
<p>A new thread is then created in a suspended state, with the start address pointing to the address of a custom loader function. This function populates the IAT, executes TLS callbacks, and finally executes the original entry point of the target application. This essentially simulates what the main thread would do if the process were being executed natively. The context of this thread is then "cloned" into the virtual CPU, and execution begins under the control of the hypervisor.</p>
<p>Memory is paged into the guest as necessary, and syscalls are intercepted, logged, and forwarded to the host OS until the virtualized target process exits.</p>
<p>As the WHP API only allows memory from the current process to be mapped into the guest, the main hypervisor logic is encapsulated within a DLL that gets injected into the target process.</p>
<h2 id="virtualcpu">Virtual CPU</h2>
<p>The WHP API provides a "friendly" wrapper around the VMX functionality described earlier, meaning that the usual steps, such as manually populating the VMCS before executing <code>VMLAUNCH</code>,  are no longer necessary. It also exposes the functionality to user-mode, meaning a custom driver is not required. However, the virtual CPU must still be initialized appropriately via WHP prior to executing the target code. The important aspects will be described below.</p>
<h3 id="controlregisters">Control registers</h3>
<p>Only the <code>CR0</code>, <code>CR3</code>, and <code>CR4</code> control registers are relevant for this project. <code>CR0</code> and <code>CR4</code> are used to enable CPU configuration options such as protected mode, paging, and PAE. <code>CR3</code> contains the physical address of the <code>PML4</code> paging table, which will be described in further detail in the Memory Paging section.</p>
<h3 id="modelspecificregisters">Model-specific registers</h3>
<p>Model-Specific Registers (MSRs) must also be initialized to ensure the correct operation of the virtual CPU. <code>MSR_EFER</code> contains flags for extended features, such as enabling long mode (64-bit) and <code>SYSCALL</code> instructions. <code>MSR_LSTAR</code> contains the address of the syscall handler, and <code>MSR_STAR</code> contains the segment selectors for transitioning to CPL0 (and back to CPL3) during syscalls. <code>MSR_KERNEL_GS_BASE</code> contains the shadow base address of the <code>GS</code> selector.</p>
<h3 id="globaldescriptortable">Global descriptor table</h3>
<p>The Global Descriptor Table (GDT) defines the segment descriptors, which essentially describe memory regions and their properties for use in protected mode.</p>
<p>In long mode, the GDT has limited use and is mostly a relic of the past - x64 always operates in a flat memory mode, meaning all selectors are based at <code>0</code>. The only exceptions to this are the <code>FS</code> and <code>GS</code> registers, which are used for thread-specific purposes. Even in those cases, their base addresses are not defined by the GDT. Instead, MSRs (such as <code>MSR_KERNEL_GS_BASE</code> described above) are used to store the base address.</p>
<p>Despite this obsolescence, the GDT is still an important part of the x64 model. For example, the current privilege level is defined by the <code>CS</code> (Code Segment) selector.</p>
<h3 id="taskstatesegment">Task state segment</h3>
<p>In long mode, the Task State Segment (TSS) is simply used to load the stack pointer when transitioning from a lower privilege level to a higher one. As this emulator operates almost exclusively in CPL3, except for the initial bootloader and interrupt handlers, only a single page is allocated for the CPL0 stack. The TSS is stored as a special system entry within the GDT and occupies two slots.</p>
<h3 id="interruptdescriptortable">Interrupt descriptor table</h3>
<p>The Interrupt Descriptor Table (IDT) contains information about each type of interrupt, such as the handler addresses. This will be described in further detail in the Interrupt Handling section.</p>
<h3 id="bootloader">Bootloader</h3>
<p>Most of the CPU fields mentioned above can be initialized using WHP wrapper functions, but support for certain fields (e.g. <code>XCR0</code>) only arrived in later versions of the WHP API (Windows 10 RS5). For completeness, the project includes a small “bootloader”, which runs at CPL0 upon startup and manually initializes the final parts of the CPU prior to executing the target code. Unlike a physical CPU, which would start in 16-bit real mode, the virtual CPU has already been initialized to run in long-mode (64-bit), making the boot process slightly more straightforward. </p>
<p>The following steps are performed by the bootloader:</p>
<ol>
<li><p>Load the GDT using the <code>LGDT</code> instruction. The source operand for this instruction specifies a 10-byte memory block which contains the base address and limit (size) of the table that was populated earlier.</p></li>
<li><p>Load the IDT using the <code>LIDT</code> instruction. The source operand for this instruction uses the same format as LGDT described above.</p></li>
<li><p>Set the TSS selector index into the task register using the <code>LTR</code> instruction. As mentioned above, the TSS descriptor exists as a special entry within the GDT (at <code>0x40</code> in this case).</p></li>
<li><p>The XCR0 register can be set using the <code>XSETBV</code> instruction. This is an additional control register which is used for optional features such as AVX. The native process executes XGETBV to get the host value, which is then copied into the guest via <code>XSETBV</code> in the bootloader. </p></li>
</ol>
<p>This is an important step because DLL dependencies that have already been loaded may have set global flags during their initialization process. For example, <code>ucrtbase.dll</code> checks if the CPU supports AVX via the <code>CPUID</code> instruction on startup and, if so, sets a global flag to allow the CRT to use AVX instructions for optimization reasons. If the virtual CPU attempts to execute these AVX instructions without explicitly enabling them in <code>XCR0</code> first, an undefined instruction exception will be raised.</p>
<ol>
<li><p>Manually update <code>DS</code>, <code>ES</code>, and <code>GS</code> data segment selectors to their CPL3 equivalents (<code>0x2B</code>). Execute the <code>SWAPGS</code> instruction to load the TEB base address from <code>MSR_KERNEL_GS_BASE</code>.</p></li>
<li><p>Finally, use the <code>SYSRET</code> instruction to transition into CPL3. Prior to the <code>SYSRET</code> instruction, <code>RCX</code> is set to a placeholder address (CPL3 entry point), and <code>R11</code> is set to the initial CPL3 RFLAGS value (<code>0x202</code>). The <code>SYSRET</code> instruction automatically switches the <code>CS</code> and <code>SS</code> segment selectors to their CPL3 equivalents from <code>MSR_STAR</code>.  </p></li>
</ol>
<p>When the <code>SYSRET</code> instruction executes, a page fault will be raised due to the invalid placeholder address in <code>RIP</code>. The emulator will catch this page fault and recognize it as a “special” address. The initial CPL3 register values will then be copied into the virtual CPU, <code>RIP</code> is updated to point to a custom user-mode loader function, and execution resumes. This function loads all DLL dependencies for the target executable, populates the IAT table, executes TLS callbacks, and then executes the original entry point. The import table and TLS callbacks are handled at this stage, rather than earlier on, to ensure their code is executed within the virtualized environment.</p>
<h2 id="memorypaging">Memory paging</h2>
<p>All memory management for the guest must be handled manually. This means a paging table must be populated and maintained, allowing the virtual CPU to translate a virtual address to a physical address.</p>
<h3 id="virtualaddresstranslation">Virtual address translation</h3>
<p>For those who are not familiar with paging in x64, the paging table has four levels: <code>PML4</code>, <code>PDPT</code>, <code>PD</code>, and <code>PT</code>. For any given virtual address, the CPU walks through each layer of the table, eventually reaching the target physical address. Modern CPUs also support 5-level paging (in case the 256TB of addressable memory offered by 4-level paging isn't enough!), but this is irrelevant for the purposes of this project.</p>
<p>The following image illustrates the format of a sample virtual address:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8395cb82e1f86956/6a7d870fc2cc094e2f24670b/5WT-image.png" alt="Breakdown of an example virtual address" title="Breakdown of an example virtual address" /></p>
<p>Using the example above, the CPU would calculate the physical page corresponding to the virtual address <code>0x7FFB7D030D10</code> via the following table entries: <code>PML4[0xFF]</code> -&gt; <code>PDPT[0x1ED]</code> -&gt; <code>PD[0x1E8]</code> -&gt; <code>PT[0x30]</code>. Finally, the offset (<code>0xD10</code>) will be added to this physical page to calculate the exact address.</p>
<p>Bits <code>48</code> - <code>63</code> within a virtual address are unused in 4-level paging and are essentially sign-extended to match bit <code>47</code>.</p>
<p>The <code>CR3</code> control register contains the physical address of the base <code>PML4</code> table. When paging is enabled (mandatory in long-mode), all other addresses within the context of the CPU refer to virtual addresses.</p>
<h3 id="pagefaults">Page faults</h3>
<p>When the guest attempts to access memory, the virtual CPU will raise a page fault exception if the requested page isn't already present in the paging table. This will trigger a VM Exit event and pass control back to the host. When this occurs, the <code>CR2</code> control register contains the requested virtual address, although the WHP API already provides this value within the VM Exit context data. The host can then map the requested page into memory (if possible) and resume execution or throw an error if the target address is invalid.</p>
<h3 id="hostguestmemorymirroring">Host/guest memory mirroring</h3>
<p>As mentioned earlier, the emulator creates a child process, and all virtual memory within that process will be mapped directly into the guest using the same address layout. The Hypervisor Platform API allows us to map virtual memory from the host user-mode process directly into the physical memory of the guest. The paging table will then map virtual addresses to the corresponding physical pages.</p>
<p>Instead of mapping the entire address space of the process upfront, a fixed number of physical pages are allocated for the guest. The emulator contains a very basic memory manager, and pages are mapped "on demand." When a page fault occurs, the requested page will be paged in, and execution resumes. If all page "slots" are full, the oldest entry is swapped out to make room for the new one.</p>
<p>In addition to using a fixed number of currently mapped pages, the emulator also uses a fixed-size page table. The size of the page table is determined by calculating the maximum possible number of tables for the amount of mapped page entries. This model results in a simple and consistent physical memory layout but comes at the cost of efficiency. In fact, the paging tables take up more space than the actual page entries.</p>
<p>There is a single PML4 table, and in the worst-case scenario, each mapped page entry will reference unique PDPT/PD/PT tables. As each table is <code>4096</code> bytes, the total page table size can be calculated using the following formula:</p>
<pre><code>PAGE_TABLE_SIZE = 4096 + (MAXIMUM_MAPPED_PAGES * 4096 * 3)
</code></pre>
<p>By default, the emulator allows for <code>256</code> pages to be mapped at any one time (<code>1024KB</code> in total). Using the formula above, we can calculate that this will require <code>3076KB</code> for the paging table, as illustrated below:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt391c47ed9d02df5d/6a7d8712e02fac39f75d35b4/8gv-image.png" alt="Diagram illustrating the physical memory map within the virtualized guest" title="Diagram illustrating the physical memory map within the virtualized guest" /></p>
<p>In practice, many of the page table entries will be shared, and a lot of the space allocated for the paging tables will remain unused. However, as this emulator functions well even with a small number of pages, this level of overhead is not a major concern.</p>
<p>The CPU maintains a hardware-level cache for the paging table known as the Translation Lookaside Buffer (TLB). When translating a virtual address to a physical address, the CPU will first check the TLB. If a matching entry is not found in the cache (known as a “TLB miss”), the paging tables will be read instead. For this reason, it is important to flush the TLB cache whenever the paging tables have been rebuilt to prevent it from falling out of sync. The simplest way to flush the entire TLB is to reset the <code>CR3</code> register value.</p>
<h2 id="syscallhandling">Syscall handling</h2>
<p>As the target program executes, any system calls that occur within the guest must be handled by the host. This emulator handles both <code>SYSCALL</code> instructions and legacy (interrupt-based) syscalls. <code>SYSENTER</code> is not used in long-mode and, therefore, is not supported by WinVisor.</p>
<h3 id="fastsyscallsyscall">Fast syscall (SYSCALL)</h3>
<p>When a <code>SYSCALL</code> instruction executes, the CPU transitions to CPL0 and loads <code>RIP</code> from <code>MSR_LSTAR</code>. In the Windows kernel, this would point to <code>KiSystemCall64</code>. <code>SYSCALL</code> instructions won't inherently trigger a VM Exit event, but the emulator sets <code>MSR_LSTAR</code> to a reserved placeholder address — <code>0xFFFF800000000000</code> in this case. When a <code>SYSCALL</code> instruction is executed, a page fault will be raised when RIP is set to this address, and the call can be intercepted. This placeholder is a kernel address in Windows and won't cause any conflicts with the user-mode address space.</p>
<p>Unlike legacy syscalls, the <code>SYSCALL</code> instruction doesn't swap the <code>RSP</code> value during the transition to CPL0, so the user-mode stack pointer can be retrieved directly from <code>RSP</code>.</p>
<h3 id="legacysyscallsint2e">Legacy syscalls (INT 2E)</h3>
<p>Legacy interrupt-based syscalls are slower and have more overhead than the <code>SYSCALL</code> instruction, but despite this, they are still supported by Windows. As the emulator already contains a framework for handling interrupts, adding support for legacy syscalls is very simple. When a legacy syscall interrupt is caught, it can be forwarded to the “common” syscall handler after some minor translations — specifically, retrieving the stored user-mode <code>RSP</code> value from the CPL0 stack.</p>
<h3 id="syscallforwarding">Syscall forwarding</h3>
<p>After the emulator creates the "main thread" whose context gets cloned into the virtual CPU, this native thread is reused as a proxy to forward syscalls to the host. Reusing the same thread maintains consistency for the TEB and any kernel state between the guest and the host. Win32k, in particular, relies on many thread-specific states, which should be reflected in the emulator.</p>
<p>When a syscall occurs, either by a <code>SYSCALL</code> instruction or a legacy interrupt, the emulator intercepts it and transfers it to a universal handler function. The syscall number is stored in the <code>RAX</code> register, and the first four parameter values are stored in <code>R10</code>, <code>RDX</code>, <code>R8</code>, and <code>R9</code>, respectively. <code>R10</code> is used for the first parameter instead of the usual <code>RCX</code> register because the <code>SYSCALL</code> instruction overwrites <code>RCX</code> with the return address. The legacy syscall handler in Windows (<code>KiSystemService</code>) also uses <code>R10</code> for compatibility, so it doesn’t need to be handled differently in the emulator. The remaining parameters are retrieved from the stack.</p>
<p>We don’t know the exact number of parameters expected for any given syscall number, but luckily, this doesn’t matter. We can simply use a fixed amount, and as long as the number of supplied parameters is greater than or equal to the actual number, the syscall will function correctly. A simple assembly stub will be dynamically created, populating all of the parameters, executing the target syscall, and returning cleanly.</p>
<p>Testing showed that the maximum number of parameters currently used by Windows syscalls is <code>17</code> (<code>NtAccessCheckByTypeResultListAndAuditAlarmByHandle</code>, <code>NtCreateTokenEx</code>, and <code>NtUserCreateWindowEx</code>). WinVisor uses <code>32</code> as the maximum number of parameters to allow for potential future expansion.</p>
<p>After executing the syscall on the host, the return value is copied to <code>RAX</code> in the guest. <code>RIP</code> is then transferred to a <code>SYSRET</code> instruction (or <code>IRETQ</code> for legacy syscalls) before resuming the virtual CPU for a seamless transition back to user-mode.</p>
<h3 id="syscalllogging">Syscall logging</h3>
<p>By default, the emulator simply forwards guest syscalls to the host and logs them to the console. However, some additional steps are necessary to convert the raw syscalls into a readable format.</p>
<p>The first step is to convert the syscall number to a name. Syscall numbers are made up of multiple parts: bits <code>12</code> - <code>13</code> contain the system service table index (<code>0</code> for <code>ntoskrnl</code>, <code>1</code> for <code>win32k</code>), and bits <code>0</code> - <code>11</code> contain the syscall index within the table. This information allows us to perform a reverse-lookup within the corresponding user-mode module (<code>ntdll</code> / <code>win32u</code>) to resolve the original syscall name.</p>
<p>The next step is to determine the number of parameter values to display for each syscall. As mentioned above, the emulator passes <code>32</code> parameter values to each syscall, even if most of them are not used. However, logging all <code>32</code> values for each syscall wouldn't be ideal for readability reasons. For example, a simple <code>NtClose(0x100)</code> call would be printed as <code>NtClose(0x100, xxx, xxx, xxx, xxx, xxx, xxx, xxx, xxx, ...)</code>. As mentioned earlier, there is no simple way to automatically determine the exact number of parameters for each syscall, but there is a trick that we can use to estimate it with high accuracy.</p>
<p>This trick relies on the 32-bit system libraries used by WoW64. These libraries use the stdcall calling convention, which means the caller pushes all parameters onto the stack, and they are cleaned internally by the callee before returning. In contrast, native x64 code places the first 4 parameters into registers, and the caller is responsible for managing the stack.</p>
<p>For example, the <code>NtClose</code> function in the WoW64 version of <code>ntdll.dll</code> ends with the <code>RET 4</code> instruction. This pops an additional 4-bytes off the stack after the return address, which implies that the function takes one parameter. If the function used <code>RET 8</code>, this would suggest that it takes 2 parameters, and so on.</p>
<p>Even though the emulator runs as a 64-bit process, we can still load the 32-bit copies of <code>ntdll.dll</code> and <code>win32u.dll</code> into memory - either manually or mapped using <code>SEC_IMAGE</code>. A custom version of <code>GetProcAddress</code> must be written to resolve the WoW64 export addresses, but this is a trivial task. From here, we can automatically find the corresponding WoW64 export for each syscall, scan for the <code>RET</code> instruction to calculate the number of parameters, and store the value in a lookup table.</p>
<p>This method is not perfect, and there are a number of ways that this could fail:</p>
<ul>
<li>A small number of native syscalls don't exist in WoW64, such as <code>NtUserSetWindowLongPtr</code>.</li>
<li>If a 32-bit function contains a 64-bit parameter, it will be split into 2x 32-bit parameters internally, whereas the corresponding 64-bit function would only require a single parameter for the same value.</li>
<li>The WoW64 syscall stub functions within Windows could change in such a way that causes the existing <code>RET</code> instruction search to fail.</li>
</ul>
<p>Despite these pitfalls, the results will be accurate for the vast majority of syscalls without having to rely on hardcoded values. In addition, these values are only used for logging purposes and won't affect anything else, so minor inaccuracies are acceptable in this context. If a failure is detected, it will revert back to displaying the maximum number of parameter values.</p>
<h3 id="syscallhooking">Syscall hooking</h3>
<p>If this project were being used for sandboxing purposes, blindly forwarding all syscalls to the host would be undesirable for obvious reasons. The emulator contains a framework that allows specific syscalls to be easily hooked if necessary.</p>
<p>By default, only <code>NtTerminateThread</code> and <code>NtTerminateProcess</code> are hooked to catch the guest process exiting.</p>
<h2 id="interrupthandling">Interrupt handling</h2>
<p>Interrupts are defined by the IDT, which is populated before the virtual CPU execution begins. When an interrupt occurs, the current CPU state is pushed onto the CPL0 stack (<code>SS</code>, <code>RSP</code>, <code>RFLAGS</code>, <code>CS</code>, <code>RIP</code>), and <code>RIP</code> is set to the target handler function.</p>
<p>As with <code>MSR_LSTAR</code> for the SYSCALL handler, the emulator populates all interrupt handler addresses with placeholder values (<code>0xFFFFA00000000000</code> - <code>0xFFFFA000000000FF</code>). When an interrupt occurs, a page fault will occur within this range, which we can catch. The interrupt index can be extracted from the lowest 8-bits of the target address (e.g., <code>0xFFFFA00000000003</code> is <code>INT 3</code>), and the host can handle it as necessary.</p>
<p>At present, the emulator only handles <code>INT 1</code> (single-step), <code>INT 3</code> (breakpoint), and <code>INT 2E</code> (legacy syscall). If any other interrupt is caught, the emulator will exit with an error.</p>
<p>When an interrupt has been handled, <code>RIP</code> is transferred to an <code>IRETQ</code> instruction, which returns to user-mode cleanly. Some types of interrupts push an additional "error code" value onto the stack - if this is the case, it must be popped prior to the <code>IRETQ</code> instruction to avoid stack corruption. The interrupt handler framework within this emulator contains an optional flag to handle this transparently.</p>
<h2 id="hypervisorsharedpagebug">Hypervisor shared page bug</h2>
<p>Windows 10 introduced a new type of shared page which is located close to <code>KUSER_SHARED_DATA</code>. This page is used by timing-related functions such as <code>RtlQueryPerformanceCounter</code> and <code>RtlGetMultiTimePrecise</code>.</p>
<p>The exact address of this page can be retrieved with <code>NtQuerySystemInformation</code>, using the <code>SystemHypervisorSharedPageInformation</code> information class. The <code>LdrpInitializeProcess</code> function stores the address of this page in a global variable (<code>RtlpHypervisorSharedUserVa</code>) during process startup.</p>
<p>The WHP API seems to contain a bug that causes the <code>WHvRunVirtualProcessor</code> function to get stuck in an infinite loop if this shared page is mapped into the guest and the virtual CPU attempts to read from it.</p>
<p>Time constraints limited the ability to fully investigate this; however, a simple workaround was implemented. The emulator patches the <code>NtQuerySystemInformation</code> function within the target process and forces it to return <code>STATUS_INVALID_INFO_CLASS</code> for <code>SystemHypervisorSharedPageInformation</code> requests. This causes the <code>ntdll</code> code to fall back to traditional methods.</p>
<h2 id="demos">Demos</h2>
<p>Some examples of common Windows executables being emulated under this virtualized environment below:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdf3ef2873a10b898/6a7d87153cab1c152d0e1aa4/Slj_Image_3.png" alt="ping.exe being emulated by WinVisor" title="ping.exe being emulated by WinVisor" /></p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt86e015f720f40a17/6a7d87176693f8709d661138/gs2_Image_4.png" alt="cmd.exe being emulated by WinVisor" title="cmd.exe being emulated by WinVisor" /></p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt358982b7d856ae8a/6a7d871a96b5a6db9d8786f5/zkL_Image_5.png" alt="notepad.exe being emulated by WinVisor, including a hooked syscall (NtUserCreateWindowEx) for demonstration purposes" title="notepad.exe being emulated by WinVisor, including a hooked syscall (NtUserCreateWindowEx) for demonstration purposes" /></p>
<h2 id="limitations">Limitations</h2>
<p>The emulator has several limitations that make it unsafe to use as a secure sandbox in its current form. </p>
<h3 id="safetyissues">Safety issues</h3>
<p>There are several ways to "escape" the VM, such as simply creating a new process/thread, scheduling asynchronous procedure calls (APCs), etc.</p>
<p>Windows GUI-related syscalls can also make nested calls directly back into user-mode from the kernel, which would currently bypass the hypervisor layer. For this reason, GUI executables such as notepad.exe are only partially virtualized when run under WinVisor.</p>
<p>To demonstrate this, WinVisor includes an <code>-nx</code> command-line switch to the emulator. This forces the entire target EXE image to be marked as non-executable in memory prior to starting the virtual CPU, causing the process to crash if the host process attempts to execute any of the code natively. However, this is still unsafe to rely on — the target application could make the region executable again or simply allocate executable memory elsewhere.</p>
<p>As the WinVisor DLL is injected into the target process, it exists within the same virtual address space as the target executable. This means the code running under the virtual CPU is able to directly access the memory within the host hypervisor module, which could potentially corrupt it. </p>
<h3 id="nonexecutableguestmemory">Non-executable guest memory</h3>
<p>While the virtual CPU is set up to support NX, all memory regions are currently mirrored into the guest with full RWX access.</p>
<h3 id="singlethreadonly">Single-thread only</h3>
<p>The emulator currently only supports virtualizing a single thread. If the target executable creates additional threads, they will be executed natively. To support multiple threads, a pseudo-scheduler could be developed to handle this in the future.</p>
<p>The Windows parallel loader is disabled to ensure all module dependencies are loaded by a single thread.</p>
<h3 id="softwareexceptions">Software exceptions</h3>
<p>Virtualized software exceptions are not currently supported. If an exception occurs, the system will call the <code>KiUserExceptionDispatcher</code> function natively as usual.</p>
<h2 id="conclusion">Conclusion</h2>
<p>As seen above, the emulator performs well with a wide range of executables in its current form. While it is currently effective for logging syscalls and interrupts, a lot of further work would be required to make it safe to use for malware analysis purposes. Despite this, the project provides an effective framework for future development.</p>
<h2 id="projectlinks">Project links</h2>
<p><a href="https://github.com/x86matthew/WinVisor">https://github.com/x86matthew/WinVisor</a></p>
<p>The author can be found on X at <a href="https://x.com/x86matthew">@x86matthew</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/winvisor-hypervisor-based-emulator</link>
    <guid isPermaLink="false">winvisor-hypervisor-based-emulator</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Elastic Security Labs]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltffc1b8d9f750ec1f/6a7d871dbd21982e8c755382/winvisor.jpg" length="0" type="image/jpeg"/>
    <pubDate>Fri, 24 Jan 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Streamlining Security: Integrating Amazon Bedrock with Elastic]]></title>
    <description><![CDATA[This article will guide you through the process of setting up the Amazon Bedrock integration and enabling Elastic's prebuilt detection rules to streamline your security operations.]]></description>
    <content:encoded><![CDATA[<h2 id="preamble">Preamble</h2>
<p>In the ever-evolving landscape of cloud computing, maintaining robust security while ensuring compliance is a critical challenge for organizations of all sizes. As businesses increasingly adopt the cloud, the complexity of managing and securing data across various platforms grows exponentially. </p>
<p><a href="https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html">Amazon Bedrock</a>, with its powerful foundation of machine learning and AI services, offers a scalable, secure environment for organizations to develop and deploy intelligent applications. However, to fully harness the potential of these innovations, it’s essential to implement a streamlined approach to security and compliance.</p>
<p>Integrating Elastic with Amazon Bedrock can significantly enhance security monitoring and compliance management within your cloud environment. This integration leverages Elastic’s search, observability, and security capabilities to optimize how you manage and secure applications and data hosted on Amazon Bedrock.  </p>
<p>Elastic’s <a href="https://www.elastic.co/security/siem">security information and event management (SIEM) capabilities</a> can be used to analyze logs and monitor events generated by applications running on Amazon Bedrock. This allows for the detection of potential security threats in real-time and automated response actions to mitigate risks.</p>
<p>This article will guide you through the process of setting up Amazon Bedrock integration and enabling our prebuilt detection rules to streamline your security operations. We will cover the following key aspects:</p>
<ol>
<li><strong>Prerequisites for Elastic Amazon Bedrock Integration:</strong> Understanding the core requirements for setting up Elastic Amazon Bedrock integration for cloud security.  </li>
<li><strong>Setting Up Amazon Bedrock Integration</strong>: Step-by-step instructions to set up Amazon Bedrock in your existing AWS infrastructure.  </li>
<li><strong>Enabling Prebuilt Security Rules</strong>: How to leverage <a href="https://www.elastic.co/guide/en/security/current/rules-ui-management.html">prebuilt rules</a> to detect high-confidence policy violations and other security threats.  </li>
<li><strong>Exploring High-Confidence Misconduct Blocks Detection:</strong> An in-depth look at a specific prebuilt rule designed to detect high-confidence misconduct blocks within Amazon Bedrocklogs.  </li>
<li><strong>Demonstrate an Exploit Case Scenario for Amazon Bedrock:</strong>  Using a sample python script to simulate interactions with an Amazon Bedrock model for testing exploit scenarios that could trigger Elastic prebuilt detection rules.</li>
</ol>
<h2 id="prerequisitesforelasticamazonbedrockintegration">Prerequisites for Elastic Amazon Bedrock Integration</h2>
<h3 id="elasticintegrationforamazonbedrock">Elastic Integration for Amazon Bedrock</h3>
<p>The Amazon Bedrock integration collects Amazon Bedrock model invocation logs and runtime metrics with Elastic Agent. For a deeper dive on the integration, documentation can be found in our <a href="https://www.elastic.co/docs/current/integrations/aws_bedrock">documentation.</a></p>
<p>Below are the list of prerequisites to have a complete and successful configuration of Amazon Bedrock Elastic Integration:</p>
<ul>
<li>AWS Account Setup  </li>
<li>Elastic Cloud Requirements  </li>
<li>Terraform (Optional)</li>
</ul>
<h4 id="awsaccountsetup">AWS Account Setup</h4>
<ul>
<li><strong>Active AWS Account</strong>: Ensure you have an active AWS account with the appropriate permissions to deploy and manage resources on Amazon Bedrock.  </li>
<li><strong>Amazon Bedrock Setup</strong>: Confirm that Amazon Bedrock is correctly configured and operational within your AWS environment. This includes setting up AI models, datasets, and other resources necessary for your applications. Refer to <a href="https://docs.aws.amazon.com/bedrock/latest/userguide/getting-started.html">Getting started with Amazon Bedrock</a> for additional information on the setup.   </li>
<li><strong>IAM Roles and Permissions</strong>: Create or configure Identity and Access Management (IAM) roles with the necessary permissions to allow Elastic to access Amazon Bedrock resources. These roles should have sufficient privileges to read logs, metrics, and traces from AWS services. Additional details of the requirements can be found in our <a href="https://www.elastic.co/docs/current/integrations/aws#requirements">AWS documentation</a>. </li>
</ul>
<h4 id="elasticcloudrequirements">Elastic Cloud Requirements</h4>
<p>| <a href="https://www.elastic.co/docs/current/integrations/aws_bedrock#changelog">Version</a> | 0.7.0 (Beta) |
| :---- | :---- |
| <strong>Compatible Kibana version(s)</strong> | 8.13.0 or higher for integration version 0.2.0 and above. Minimum Kibana Version 8.12.0 |
| <a href="https://www.elastic.co/docs/current/integrations/serverless/support"><strong>Supported Serverless project types</strong></a> | Security Observability |
| <a href="https://www.elastic.co/subscriptions"><strong>Subscription level</strong></a> | Basic |
| <a href="https://www.elastic.co/docs/current/integrations/support"><strong>Level of support</strong></a> | Elastic |</p>
<p><strong>Note:</strong>  Since the integration is in Beta Release Stage, please enable <strong><em>Display Beta Integrations in the browse integration section of the Management pane in your Elastic stack.</em></strong></p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7b2d68dfda7788f2/6a7d8531448e4e23d55bdbae/image1.png" alt="" /></p>
<h4 id="terraform">Terraform</h4>
<p><a href="https://www.terraform.io/">Terraform</a> is an open source infrastructure-as-code (IaC) tool created by HashiCorp that allows you to define, provision, and manage cloud and on-premises infrastructure in a consistent and repeatable way.   </p>
<p>This is an optional step, but good to have as the next sections of the article we use this tool to set up the required AWS Infrastructure. Deep dive on installation and docs can be found <a href="https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli">here</a>.</p>
<h2 id="settingupamazonbedrockintegration">Setting Up Amazon Bedrock Integration</h2>
<p>In this section of the article, we will walk through the steps to set up Amazon Bedrock integration with Elastic in two parts: </p>
<ol>
<li><strong>Setting Up AWS Infrastructure with Terraform</strong>: In this section, we'll walk through the steps to set up an AWS infrastructure using Terraform. We'll create an S3 bucket, an EC2 instance with the necessary IAM roles and policies to access the S3 bucket, and configure security groups to allow SSH access. This setup is ideal for scenarios where you need an EC2 instance to interact with S3, such as for data processing or storage.  </li>
<li><strong>Elastic Agent and Integration Setup</strong>: In this section, we'll walk through the steps to install Elastic Agent on the AWS EC2 instance and Configure the Amazon Bedrock Integration. </li>
</ol>
<h3 id="settingupawsinfrastructurewithterraform">Setting Up AWS Infrastructure with Terraform</h3>
<p>The high-level configuration process will involve the following steps:</p>
<ol>
<li>Configuring <code>providers.tf</code>  </li>
<li>Configuring <code>variables.tf</code> </li>
<li>Configuring <code>outputs.tf</code>  </li>
<li>Configuring <code>main.tf</code></li>
</ol>
<p>The <code>providers.tf</code> file typically contains the configuration for any Terraform providers you are using in your project. In our example, it includes the configuration for the AWS provider. Here is the <a href="https://gist.github.com/shashank-elastic/290218cd4e787f65fbcbfd6423a0ca85#file-providers-tf">sample content</a> of our <code>providers.tf</code> file. The <code>profile</code> mentioned in the <code>providers.tf</code> should be configured in the user’s space of the AWS credentials file <code>(~/.aws/credentials)</code>. Refer to <a href="https://docs.aws.amazon.com/cli/v1/userguide/cli-configure-files.html#cli-configure-files-format-profile">Configuration and credential file settings - AWS Command Line Interface</a>, which is also highlighted in the credential section of Elastic’s <a href="https://www.elastic.co/docs/current/integrations/aws#aws-credentials">AWS documentation</a>.</p>
<p>The <code>variables.tf</code> file contains the variable definitions used throughout your Terraform configuration. For our scenario, it includes the definition for the aws_region and resource_labels. Here is the <a href="https://gist.github.com/shashank-elastic/290218cd4e787f65fbcbfd6423a0ca85#file-variables-tf">sample content</a> of our <code>variables.tf</code> file.</p>
<p>The <code>outputs.tf</code> file typically contains the output definitions for your Terraform configuration. These outputs can be used to display useful information after your infrastructure is provisioned. Here is the <a href="https://gist.github.com/shashank-elastic/290218cd4e787f65fbcbfd6423a0ca85#file-outputs-tf">sample content</a> of our <code>outputs.tf</code> file</p>
<p>The <code>main.tf</code> file typically contains the collection of all of these resources such as data sources, S3 bucket and bucket policy, Amazon Bedrock Model Invocation Log configuration, SQS Queue configuration, IAM Role and Policies required by the EC2 instance that would install Elastic Agent and stream logs and Amazon Bedrock Guardrail configuration. Here is the <a href="https://gist.github.com/shashank-elastic/290218cd4e787f65fbcbfd6423a0ca85#file-main-tf">sample content</a> of our <code>main.tf</code> file.</p>
<p>Once the <code>main.tf</code> is configured according to the requirements we can then initialize, plan and apply the terraform configuration.</p>
<pre><code>terraform init // initializes the directory and sets up state files in backend
terraform plan // command creates an execution plan
terraform apply // command applies the configuration aka execution step
</code></pre>
<p>To tear down the infrastructure that terraform has previously created one can use the <code>terraform destroy</code> command.</p>
<p>Once the infrastructure setup is completed, necessary resource identifiers are provided via <code>outputs.tf.</code> We can conduct a basic verification of the infrastructure created using the following steps: </p>
<ol>
<li>Verify the S3 Bucket created from the Terraform, one can either use aws cli command reference <a href="https://docs.aws.amazon.com/cli/latest/reference/s3api/list-buckets.html">list-buckets — AWS CLI 1.34.10 Command Reference</a> or navigate via AWS console to verify the same. 2. Verify the SQS Queue created from the terraform, one can either use aws cli command reference <a href="https://docs.aws.amazon.com/cli/latest/reference/sqs/list-queues.html">list-queues — AWS CLI 1.34.10 Command Reference</a> or navigate via AWS console to verify the same.  </li>
<li>Verify the EC2 Instance created from the AWS console and connect to the ec2-instance via <a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-connect-methods.html#ec2-instance-connect-connecting-console">Connect using EC2 Instance Connect - Amazon Elastic Compute Cloud</a> and run <code>aws s3 ls example-bucket-name</code> to check if the instance has access to the created S3 bucket.  </li>
<li>Verify the Amazon Bedrock Guardrail created from the Terraform, once can either use Amazon Bedrock API <a href="https://docs.aws.amazon.com/bedrock/latest/APIReference/API_ListGuardrails.html">ListGuardrails - Amazon Bedrock</a> or navigate via AWS console to verify the same.</li>
</ol>
<h3 id="settingupelasticagentandintegrationsetup">Setting Up Elastic Agent and Integration Setup</h3>
<p>To install Elastic Agent on the AWS EC2 instance and configure the Amazon Bedrock integration, create an agent policy using the guided steps in <a href="https://www.elastic.co/guide/en/fleet/current/agent-policy.html">Elastic Agent policies | Fleet and Elastic Agent Guide [8.15]</a>. Then log into to the ec2-instance created in the infrastructure setup steps via <a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-connect-methods.html#ec2-instance-connect-connecting-console">Connect using EC2 Instance Connect - Amazon Elastic Compute Cloud</a>, and install the elastic agent using the guided steps in <a href="https://www.elastic.co/guide/en/fleet/current/elastic-agent-installation.html">Install Elastic Agents | Fleet and Elastic Agent Guide [8.15]</a>. During the agent installation, remember to select the agent policy created at the beginning of this setup process and use the relevant agent installation method depending on the instance created. Finally, ensure the agent is properly configured and there is incoming data from the agent.</p>
<p>To configure the Amazon Bedrock integration in the newly-created policy, add the Amazon Bedrock integration using the guided steps: <a href="https://www.elastic.co/guide/en/fleet/current/add-integration-to-policy.html">Add an Elastic Agent integration to a policy</a>. Enable Beta Integrations to use Amazon Bedrock integration as displayed in the image below. </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt82c23c9b24d905c9/6a7d8534fc63ab960464a020/image4.png" alt="" /></p>
<p>Configure the Integration with AWS Access Keys to access the AWS account where Amazon Bedrock is configured. Use the Collect Logs from S3 bucket and specify the Bucket ARN created in the setup step. Please note to use either the S3 Bucket or the SQS Queue URL during the setup and <em>not both</em>. Add this integration to the existing policy where the ec2-instance is configured.   </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3f7700e42e7b4ecd/6a7d85363cab1c01ad0e1a6e/image8.png" alt="" /></p>
<h3 id="verifyamazonbedrockmodelinvocationlogingestions">Verify Amazon Bedrock Model Invocation Log Ingestions</h3>
<p>Once the Elastic Agent and integration setup is completed, we can conduct a basic verification of the integration to determine if the logs are being ingested as expected  by using the following example API call: </p>
<pre><code>aws bedrock-runtime converse \
--model-id "anthropic.claude-3-5-sonnet-20240620-v1:0" \
--messages '[{"role":"user","content":[{"text":"Hello "}]}]' \
--inference-config '{"maxTokens":2000,"stopSequences":[],"temperature":1,"topP":0.999}' \
--additional-model-request-fields '{"top_k":250}' \
--region us-east-1
</code></pre>
<p>The example API call assumes a working setup with aws cli and there is access for the foundational model <a href="https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic-claude-messages.html">Anthropic Claude Messages API - Amazon Bedrock</a>. If the user does not have access to the model one can simply request access for models from the model-access page as suggested in <a href="https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html">Access Amazon Bedrock foundation models</a>, or we can optionally change the API call to any existing model the user can access. </p>
<p>On successful execution of the above API call, the Amazon Bedrock Model invocation logs are populated and in Kibana <code>logs-aws_bedrock.invocation-default</code> should be populated with those invocation logs. We can use the following simple ES|QL query to return recently ingested events.</p>
<pre><code>from logs-aws_bedrock.invocation-* | LIMIT 10
</code></pre>
<h2 id="enableprebuiltdetectionrules">Enable Prebuilt Detection Rules</h2>
<p>To enable prebuilt detection rules, first login to the elastic instance and from the left pane navigation navigate to Security → Rules → Detection rules (SIEM). Filter for “Data Source: Amazon Bedrock” from the tags section. </p>
<p>Enable the available prebuilt rules. For prebuilt rules, the Setup information contains a helper guide to setup AWS Guardrails for Amazon Bedrock, which is accomplished in the <a href="https://www.elastic.co/security-labs/blog/streamlining-security-integrating-amazon-bedrock?tab=t.0#bookmark=id.5wbf10usmxhz">Setting Up AWS Infrastructure with Terraform</a> step if the example is followed correctly and the terraform has the Amazon Bedrock Guardrail configuration. Please note this setup is vital for some of the rules to generate alerts–we need to ensure the guardrail is set up accordingly if skipped in the infrastructure setup stage.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt32fc9de84b7de2de/6a7d853a63e95966ac73af15/image3.png" alt="" /></p>
<h2 id="exploringhighconfidencemisconductblocksdetection">Exploring High-Confidence Misconduct Blocks Detection</h2>
<p>Let’s simulate a real world scenario in which a user queries a topic denied to the Amazon Bedrock model. Navigate to the Amazon Bedrock section in the Amazon UI Console, and use the left navigation pane to navigate to the Guardrails subsection under Safeguards. Use the sample guardrail created during our setup instructions for this exercise, and use the test option to run a model invocation with the guardrails and query the denied topic configured.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte2c03823ad964406/6a7d853d96b5a67a6e8786b9/image6.png" alt="" /></p>
<p>Repeat the query at least 6 times as the prebuilt rule is designed to alert on greater than 5 high confidence blocks. When the Alert schedule runs, we can see an alert populate for <code>Unusual High Confidence Misconduct Blocks Detected.</code></p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt817db9414e0f21b9/6a7d854048511b343ce7d3e3/image7.png" alt="" /></p>
<h2 id="demonstrateanexploitcasescenarioforamazonbedrock">Demonstrate an Exploit Case Scenario for Amazon Bedrock</h2>
<p>To simulate an Amazon Bedrock Security bypass, we need an exploit simulation script to interact with Amazon Bedrock models. The exploit script example we provide simulates the following attack pattern: </p>
<ul>
<li>Attempts multiple successive requests to use denied model resources within AWS Bedrock   </li>
<li>Generates multiple successive validation exception errors within Amazon Bedrock  </li>
<li>User consistently generates high input token counts, submits numerous requests, and receives large responses that mimic patterns of resource exhaustion  </li>
<li>Combines repeated high-confidence 'BLOCKED' actions coupled with specific violation codes such as 'MISCONDUCT', indicating persistent misuse or attempts to probe the model's ethical boundaries</li>
</ul>
<pre><code>class BedrockModelSimulator:
   def __init__(self, profile_name, region_name):
       // Create a Boto3 Session Client for Ineration 
   def generate_args_invoke_model(self, model_id, user_message, tokens):     // Generate Model Invocation parameters
       guardrail_id = &lt;&lt;GUARDRAIL_ID&gt;&gt;
       guardrail_version = &lt;&lt;GUARDRAIL_VERSION&gt;&gt;

       guardrail_config = {
           "guardrailIdentifier": guardrail_id,
           "guardrailVersion": guardrail_version,
           "trace": "enabled"
       }
       conversation = [
           {
               "role": "user",
               "content": [{"text": user_message}],
           }
       ]
       inference_config = {"maxTokens": tokens, "temperature": 0.7, "topP": 1}
       additional_model_request_fields = {}

       kwargs = {
           "modelId": model_id,
           "messages": conversation,
           "inferenceConfig": inference_config,
           "additionalModelRequestFields": additional_model_request_fields
        "guardrailConfig" : guardrail_config
       }
       return kwargs

   def invoke_model(self, invocation_arguments):
       for  in range(count):
           try:
               // Invoke Model With right invocation_arguments
           except ClientError as e:
               // Error meesage

def main():
   profile_name = &lt;&lt;AWS Profile&gt;&gt;
   region_name = 'us-east-1'
   denied_model_id = // Use a denied model   
   denied_model_user_message = // Sample Message 
   available_model_id = // Use an available model  
   validation_exception_user_message = // Sample Message 
   resource_exploit_user_message = // A very big message for resource exhuastion
   denied_topic_user_message = // Sample Message that can query denied topic configured
   simulator = BedrockModelSimulator(profile_name, region_name)
   denied_model_invocation_arguments = simulator.generate_args_invoke_model(denied_model_id, denied_model_user_message, 200)
   simulator.invoke_model(denied_model_invocation_arguments)
   validation_exception_invocation_arguments = simulator.generate_args_invoke_model(available_model_id, validation_exception_user_message, 6000)
   simulator.invoke_model(validation_exception_invocation_arguments)
   resource_exhaustion_invocation_arguments = simulator.generate_args_invoke_available_model(available_model_id, resource_exploit_user_message, 4096)
   simulator.invoke_model(resource_exhaustion_invocation_arguments)
   denied_topic_invocation_arguments = simulator.generate_args_invoke_available_model_guardrail(available_model_id, denied_topic_user_message, 4096)
   simulator.invoke_model(denied_topic_invocation_arguments)

if __name__ == "__main__":
   main()
</code></pre>
<p><strong>Note:</strong> The GUARDRAIL_ID and GUARDRAIL_VERSION can be found in <code>outputs.tf</code> </p>
<p>When executed in a controlled environment, the provided script simulates an exploit scenario that would generate detection alerts in Elastic Security. When analyzing these alerts using the Elastic Attack Discovery feature, the script creates attack chains that show the relationships between various alerts, giving analysts a clear understanding of how multiple alerts might be part of a larger attack.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt61b70e9b70da7473/6a7d854396b5a61a3d8786c1/image2.png" alt="" /></p>
<h2 id="conclusion">Conclusion</h2>
<p>Integrating Elastic with Amazon Bedrock empowers organizations to maintain a secure and compliant cloud environment while maximizing the benefits of AI and machine learning. By leveraging Elastic’s advanced security and observability tools, businesses can proactively detect threats, automate compliance reporting, and gain deeper insights into their cloud operations. Increasingly, enterprises rely on opaque data sources and technologies to reveal the most serious threats-- our commitment to transparent security is evident in our open artifacts, integrations, and source code.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/streamlining-security-integrating-amazon-bedrock</link>
    <guid isPermaLink="false">streamlining-security-integrating-amazon-bedrock</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Shashank K S]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7e166c4eec44ed0b/6a7d85463ce8e2d05acf26da/Security_Labs_Images_36.jpg" length="0" type="image/jpeg"/>
    <pubDate>Thu, 14 Nov 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[STIXy Situations: ECSaping your threat data]]></title>
    <description><![CDATA[Structured threat data is commonly formatted using STIX. To help get this data into Elasticsearch, we’re releasing a Python script that converts STIX to an ECS format to be ingested into your stack.]]></description>
    <content:encoded><![CDATA[<h2 id="preamble">Preamble</h2>
<p>Organizations that use threat indicators or observables consume, create, and/or (ideally) publish threat data. This data can be used internally or externally as information or intelligence to inform decision-making and event prioritization.</p>
<p>While there are several formats for this information to be structured into, the de facto industry standard is <a href="https://oasis-open.github.io/cti-documentation/stix/intro">Structured Threat Information Expression (STIX)</a>. STIX is managed by the <a href="https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=cti">OASIS Cyber Threat Intelligence Technical Committee</a> and enables organizations to share threat data in a standard and machine-readable format.</p>
<p>At Elastic, we developed the <a href="https://www.elastic.co/guide/en/ecs/current/ecs-reference.html">Elastic Common Schema (ECS)</a> as a data normalization capability. “[ECS] is an open source specification, developed with support from the Elastic user community. ECS defines a common set of fields for storing event data in Elasticsearch, such as logs and metrics.” In April of 2023, <a href="https://www.elastic.co/blog/ecs-elastic-common-schema-otel-opentelemetry-announcement">Elastic contributed ECS</a> to the <a href="https://opentelemetry.io/docs/concepts/semantic-conventions/">OpenTelemetry Semantic Conventions (OTel)</a> as a commitment to the joint development of an open schema. </p>
<p>The security community shares threat data in the STIX format, so to store that data in Elasticsearch for analysis and threat detection [<a href="https://www.elastic.co/guide/en/security/current/threat-intel-hash-indicator-match.html">1</a>] [<a href="https://www.elastic.co/guide/en/security/current/threat-intel-ip-address-indicator-match.html">2</a>] [<a href="https://www.elastic.co/guide/en/security/current/threat-intel-url-indicator-match.html">3</a>] [<a href="https://www.elastic.co/guide/en/security/current/threat-intel-windows-registry-indicator-match.html">4</a>], we created a tool that converts STIX documents into ECS and outputs the threat data either as a file or directly into Elasticsearch indices. If this was a challenge for us, it was a challenge for others - therefore, we decided to release a version of the tool.</p>
<p>This tool uses the <a href="https://www.elastic.co/licensing/elastic-license">Elastic License 2.0</a> and is available for download <a href="https://github.com/elastic/labs-releases/tree/main/tools/stix-to-ecs">here</a>.</p>
<h2 id="gettingstarted">Getting started</h2>
<p>This project will take a STIX 2.x formatted JSON document and create an ECS version. There are three output options: STDOUT as JSON, an NDJSON file, and/or directly to an Elasticsearch cluster.</p>
<h3 id="prerequisites">Prerequisites</h3>
<p>The STIX 2 ECS project requires Python 3.10+ and the <a href="https://pypi.org/project/stix2/">stix2</a>, <a href="https://pypi.org/project/elasticsearch/">Elasticsearch</a>, and <a href="https://pypi.org/project/getpass4/">getpass</a> modules.</p>
<p>If exporting to Elasticsearch, you will need the host information and authentication credentials. API authentication is not yet implemented.</p>
<h3 id="setup">Setup</h3>
<p>Create a virtual environment and install the required prerequisites.</p>
<pre><code>git clone https://github.com/elastic/labs-releases.git
cd tools/stix2ecs
python -m venv /path/to/virtual/environments/stix2ecs
source /path/to/virtual/environments/stix2ecs/bin/activate
python -m pip install -r requirements.txt
</code></pre>
<h2 id="operation">Operation</h2>
<p>The input is a STIX 2.x JSON document (or a folder of JSON documents); the output defaults to STDOUT, with an option to create an NDJSON file and/or send to an Elasticsearch cluster.</p>
<pre><code>stix_to_ecs.py [-h] -i INPUT [-o OUTPUT] [-e] [--index INDEX] [--url URL] \
[--user USER] [-p PROVIDER] [-r]
</code></pre>
<p>By default, the ECS file is named the same as the STIX file input but with <code>.ecs.ndjson</code> appended.</p>
<h3 id="arguments">Arguments</h3>
<p>The script has several arguments, the only mandatory field is <code>-i</code> for the input. By default, the script will output the NDJSON document to STDOUT.</p>
<p>| Option | Description |
| - | - |
| -h | displays the help menu |
| -i | specifies the input STIX document (mandatory) |
| -o | specifies the output ECS document (optional) |
| -p | defines the ECS provider field (optional) |
| -r | recursive mode to convert multiple STIX documents (optional) |
| -e | specifies the Elasticsearch output mode (optional) |
| --index | defines the Elasticsearch Index, requires <code>-e</code> (optional) |
| --url | defines the Elasticsearch URL, requires <code>-e</code> (optional) |
| --user | defines the Elasticsearch username, requires <code>-e</code> (optional) |</p>
<h2 id="examples">Examples</h2>
<p>There are two sample files located in the <code>test-inputs/</code> directory. One is from <a href="https://www.cisa.gov/topics/cyber-threats-and-advisories/information-sharing/automated-indicator-sharing-ais">CISA</a> (Cybersecurity &amp; Infrastructure Security Agency), and one is from <a href="https://github.com/OpenCTI-Platform/opencti">OpenCTI</a> (an open source threat intelligence platform).</p>
<h3 id="stixfileinputtostdout">STIX file input to STDOUT</h3>
<p>This will output the STIX document to STDOUT in ECS format.</p>
<pre><code>python stix_to_ecs.py -i test-inputs/cisa_sample_stix.json | jq

[
  {
    "threat": {
      "indicator": {
        "file": {
          "name": "123.ps1",
          "hash": {
            "sha256": "ED5D694D561C97B4D70EFE934936286FE562ADDF7D6836F795B336D9791A5C44"
          }
        },
        "type": "file",
        "description": "Simple indicator of observable {ED5D694D561C97B4D70EFE934936286FE562ADDF7D6836F795B336D9791A5C44}",
        "first_seen": "2023-11-21T18:57:25.000Z",
        "provider": "identity--b3bca3c2-1f3d-4b54-b44f-dac42c3a8f01",
        "modified_at": "2023-11-21T18:57:25.000Z",
        "marking": {
          "tlp": "clear"
        }
      }
    }
  },
...
</code></pre>
<h3 id="stixfileinputtoecsfileoutput">STIX file input to ECS file output</h3>
<p>This will create a folder called <code>ecs</code> in the present directory and write the ECS file there.</p>
<pre><code>python python stix_to_ecs.py -i test-inputs/cisa_sample_stix.json -o ecs

cat ecs/cisa_sample_stix.ecs.ndjson | jq
{
  "threat": {
    "indicator": {
      "file": {
        "name": "123.ps1",
        "hash": {
          "sha256": "ED5D694D561C97B4D70EFE934936286FE562ADDF7D6836F795B336D9791A5C44"
        }
      },
      "type": "file",
      "description": "Simple indicator of observable {ED5D694D561C97B4D70EFE934936286FE562ADDF7D6836F795B336D9791A5C44}",
      "first_seen": "2023-11-21T18:57:25.000Z",
      "provider": "identity--b3bca3c2-1f3d-4b54-b44f-dac42c3a8f01",
      "modified_at": "2023-11-21T18:57:25.000Z",
      "marking": {
        "tlp": "clear"
      }
    }
  }
}
...
</code></pre>
<h3 id="stixfileinputtoecsfileoutputdefiningtheproviderfield">STIX file input to ECS file output, defining the Provider field</h3>
<p>The provider field is commonly a GUID in the STIX document. To make it more user-friendly, you can use the <code>-p</code> argument to define the <code>threat.indicator.provider</code> field.</p>
<pre><code>python stix_to_ecs.py -i test-inputs/cisa_sample_stix.json -o ecs -p "Elastic Security Labs"

cat ecs/cisa_sample_stix.ecs.ndjson | jq
{
  "threat": {
    "indicator": {
      "file": {
        "name": "123.ps1",
        "hash": {
          "sha256": "ED5D694D561C97B4D70EFE934936286FE562ADDF7D6836F795B336D9791A5C44"
        }
      },
      "type": "file",
      "description": "Simple indicator of observable {ED5D694D561C97B4D70EFE934936286FE562ADDF7D6836F795B336D9791A5C44}",
      "first_seen": "2023-11-21T18:57:25.000Z",
      "provider": "Elastic Security Labs",
      "modified_at": "2023-11-21T18:57:25.000Z",
      "marking": {
        "tlp": "clear"
      }
    }
  }
}
...
</code></pre>
<h3 id="stixdirectoryinputtoecsfileoutputs">STIX directory input to ECS file outputs</h3>
<p>If you have a directory of STIX documents, you can use the <code>-r</code> argument to recursively search through the directory and write the ECS documents to the output directory.</p>
<pre><code>python stix_to_ecs.py -ri test-inputs -o ecs
</code></pre>
<h3 id="stixfileinputtoelasticsearchoutput">STIX file input to Elasticsearch output</h3>
<p>To output to Elasticsearch, you can use either Elastic Cloud or a local instance. Local Elasticsearch will use port <code>9200</code> and Elastic Cloud will use port <code>443</code>. By default, a valid TLS session to Elasticsearch is required.</p>
<p>First, create an index if you don't already have one. In this example, we’re creating an index called <code>stix2ecs</code>, but the index name isn’t relevant.</p>
<pre><code>curl -u {username} -X PUT "https://elasticsearch:port/stix2ecs?pretty"

{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "stix2ecs"
}
</code></pre>
<p>Next, define the Elasticsearch output options.</p>
<pre><code>python stix_to_ecs.py -i test-inputs/cisa_sample_stix.json -e --url https://elasticsearch:port --user username --index stix2ecs
</code></pre>
<p>If you’re storing the data in Elasticsearch for use in another platform, you can view the indicators using cURL.</p>
<pre><code>curl -u {username} https://elasticsearch:port/stix2ecs/_search?pretty

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "stix2ecs",
        "_id" : "n2lt8IwBahlUtp0hzm9i",
        "_score" : 1.0,
        "_source" : {
          "threat" : {
            "indicator" : {
              "file" : {
                "name" : "123.ps1",
                "hash" : {
                  "sha256" : "ED5D694D561C97B4D70EFE934936286FE562ADDF7D6836F795B336D9791A5C44"
                }
              },
              "type" : "file",
              "description" : "Simple indicator of observable {ED5D694D561C97B4D70EFE934936286FE562ADDF7D6836F795B336D9791A5C44}",
              "first_seen" : "2023-11-21T18:57:25.000Z",
              "provider" : "identity--b3bca3c2-1f3d-4b54-b44f-dac42c3a8f01",
              "modified_at" : "2023-11-21T18:57:25.000Z",
              "marking" : {
                "tlp" : "clear"
              }
            }
          }
        }
      }
...
</code></pre>
<p>If you’re using Kibana, you can <a href="https://www.elastic.co/guide/en/kibana/current/data-views.html">create a Data View</a> for your <code>stix2ecs</code> index to view the ingested indicators. </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6cee6cc3e7a33b0c/6a7d847d63e959b55f73aef1/image1.png" alt="STIX2ECS data in Kibana" title="STIX2ECS data in Kibana" /></p>
<p>Finally, you can use this as an indicator source for <a href="https://www.elastic.co/guide/en/security/current/prebuilt-rule-1-0-2-threat-intel-indicator-match.html">Indicator Match rules</a>.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltce2931fe22c07948/6a7d84803ce8e27ae8cf26b8/image2.png" alt="Indicator Match rule created with STIX2ECS data" title="Indicator Match rule created with STIX2ECS data" /></p>
<h2 id="summary">Summary</h2>
<p>We hope this project helps your organization analyze and operationalize your threat data. If you’re new to the Elastic Common Schema, you can learn more about that <a href="https://www.elastic.co/guide/en/ecs/current/index.html">here</a>. </p>
<p>As always, please feel free to open an <a href="https://github.com/elastic/labs-releases/issues">issue</a> with any questions, comments, concerns, or complaints. </p>
<h2 id="aboutelasticsecuritylabs">About Elastic Security Labs</h2>
<p>Elastic Security Labs is the threat intelligence branch of Elastic Security dedicated to creating positive change in the threat landscape. Elastic Security Labs provides publicly available research on emerging threats with an analysis of strategic, operational, and tactical adversary objectives, then integrates that research with the built-in detection and response capabilities of Elastic Security.</p>
<p>Follow Elastic Security Labs on Twitter <a href="https://twitter.com/elasticseclabs?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor">@elasticseclabs</a> and check out our research at <a href="https://www.elastic.co/security-labs/">www.elastic.co/security-labs/</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/stixy-situations-ecsaping-your-threat-data</link>
    <guid isPermaLink="false">stixy-situations-ecsaping-your-threat-data</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Cyril François,Andrew Pease]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd6787600d161b223/6a7d8483c2cc0955432466c3/photo-edited-07@2x.jpg" length="0" type="image/jpeg"/>
    <pubDate>Fri, 09 Feb 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Streamlining ES|QL Query and Rule Validation: Integrating with GitHub CI]]></title>
    <description><![CDATA[ES|QL is Elastic's new piped query language. Taking full advantage of this new feature, Elastic Security Labs walks through how to run validation of ES|QL rules for the Detection Engine.]]></description>
    <content:encoded><![CDATA[<p>One of the amazing, recently premiered <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/release-highlights.html">8.11.0 features</a>, is the Elasticsearch Query Language (<a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html">ES|QL</a>). As highlighted in an earlier <a href="https://www.elastic.co/blog/elasticsearch-query-language-esql">post by Costin Leau</a>, it’s a full-blown, specialized query and compute engine for Elasitcsearch. Now that it’s in technical preview, we wanted to share some options to <em>validate</em> your ES|QL queries. This overview is for engineers new to ES|QL. Whether you’re searching for insights in Kibana or investigating security threats in <a href="https://www.elastic.co/guide/en/security/current/timelines-ui.html">Timelines</a>, you’ll see how this capability is seamlessly interwoven throughout Elastic.       </p>
<h2 id="esqlvalidationbasicsftkibanaelasticsearch">ES|QL validation basics ft. Kibana &amp; Elasticsearch</h2>
<p>If you want to quickly validate a single query, or feel comfortable manually testing queries one-by-one, the Elastic Stack UI is all you need. After navigating to the Discover tab in Kibana, click on the "<strong>Try ES|QL</strong>" Technical Preview button in the Data View dropdown to load the query pane. You can also grab sample queries from the  <a href="https://www.elastic.co/guide/en/elasticsearch/reference/master/esql-examples.html">ES|QL Examples</a> to get up and running. Introducing non-<a href="https://www.elastic.co/guide/en/ecs/current/index.html">ECS</a> fields will immediately highlight errors prioritizing syntax errors, then unknown column errors.  </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5226bb93f363731f/6a7d85086693f84a786610f6/image7.png" alt="" /></p>
<p>In this example, there are two syntax errors that are highlighted:  </p>
<ul>
<li>the invalid syntax error on the input <code>wheres</code> which should be <code>where</code> and  </li>
<li>the unknown column <code>process.worsking_directory</code>, which should be <code>process.working_directory</code>.  </li>
</ul>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc34db3ace9911415/6a7d850b437e0f2650dd8623/image3.png" alt="" /></p>
<p>After resolving the syntax error in this example, you’ll observe the Unknown column errors. Here are a couple reasons this error may appear: </p>
<ul>
<li><strong>Fix Field Name Typos</strong>: Sometimes you simply need to fix the name as suggested in the error; consult the ECS or any integration schemas and confirm the fields are correct</li>
<li><strong>Add Missing Data</strong>: If you’re confident the fields are correct, sometimes adding data to your stack, which will populate the columns</li>
<li><strong>Update Mapping</strong>: You can configure <a href="https://www.elastic.co/guide/en/elasticsearch/reference/8.11/mapping.html">Mappings</a> to set explicit fields, or add new fields to an existing data stream or index using the <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html">Update Mapping API</a> </li>
</ul>
<h2 id="esqlwarnings">ES|QL warnings</h2>
<p>Not all fields will appear as errors, in which case you’re presented with warnings and a dropdown list. Hard failures (e.g. errors), imply that the rule cannot execute, whereas warnings indicate that the rule can run, but the functions may be degraded.  </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt50b8cc0e3aa56553/6a7d850eb437701a5c4d3fe0/image6.png" alt="" /></p>
<p>When utilizing broad ES|QL queries that span multiple indices, such as <code>logs-* | limit 10</code>, there might be instances where certain fields fail to appear in the results. This is often due to the fields being undefined in the indexed data, or not yet supported by ES|QL. In cases where the expected fields are not retrieved, it's typically a sign that the data was ingested into Elasticsearch without these fields being indexed, as per the established mappings. Instead of causing the query to fail, ES|QL handles this by returning "null" for the unavailable fields, serving as a warning that something in the query did not execute as expected. This approach ensures the query still runs, distinguishing it from a hard failure, which occurs when the query cannot execute at all, such as when a non-existent field is referenced.  </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt04edca62615fef66/6a7d85113cab1c0c510e1a62/image12.png" alt="" /></p>
<p>There are also helpful performance warnings that may appear. Providing a <code>LIMIT</code> parameter to the query will help address performance warnings. Note this example highlights that there is a default limit of 500 events returned. This limit may significantly increase once this feature is generally available. </p>
<h2 id="security">Security</h2>
<p>In an investigative workflow, security practitioners prefer to iteratively hunt for threats, which may encompass manually testing, refining, and tuning a query in the UI. Conveniently, security analysts and engineers can natively leverage ES|QL in timelines, with no need to interrupt workflows by pivoting back and forth to a different view in Kibana. You’ll receive the same errors and warnings in the same security component, which shows Elasticsearch feedback under the hood.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte19e78f1f100d59d/6a7d8514e3a219360a99c76c/image1.png" alt="" /></p>
<p>In some components, you will receive additional feedback based on the context of where ES|QL is implemented. One scenario is when you create an ES|QL rule using the create new rule feature under the Detection Rules (SIEM) tab.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt76a126b36aecc868/6a7d8517227b1c088559587e/image8.png" alt="" /></p>
<p>For example, this query could easily be converted to an <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/eql.html">EQL</a> or <a href="https://www.elastic.co/guide/en/kibana/current/kuery-query.html">KQL</a> query as it does not leverage powerful features of ES|QL like statistics, frequency analysis, or parsing unstructured data. If you want to learn more about the benefits of queries using ES|QL check out this <a href="https://www.elastic.co/blog/elasticsearch-query-language-esql">blog by Costin</a>, which covers performance boosts. In this case, we must add <code>[metadata _id, _version, _index]</code> to the query, which informs the UI which components to return in the results.</p>
<h2 id="apicallsofcourse">API calls? Of course!</h2>
<p>Prior to this section, all of the examples referenced creating ES|QL queries and receiving feedback directly from the UI. For illustrative purposes, the following examples leverage Dev Tools, but these calls are easily migratable to cURL bash commands or the language / tool of your choice that can send an HTTP request.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbaf05a934b9227e5/6a7d851973d9bdd55629ac82/image4.png" alt="" /></p>
<p>Here is the same query as previously shown throughout other examples, sent via a POST request to the <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-query-api.html">query API</a> with a valid query.  </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt76cab04afe8cb66a/6a7d851c05b7b5047e188bb9/image10.png" alt="" /></p>
<p>As expected, if you supply an invalid query, you’ll receive similar feedback observed in the UI. In this example, we’ve also supplied the <code>?error_trace</code> flag which can provide the stack trace if you need additional context for why the query failed validation. </p>
<p>As you can imagine, we can use the API to programmatically validate ES|QL queries. You can also still use the <a href="https://www.elastic.co/guide/en/kibana/current/create-rule-api.html">Create rule</a> Kibana API, which requires a bit more metadata associated with a security rule. However, if you want to only validate a query, the <code>_query</code> API comes in handy. From here you can use the <a href="https://www.elastic.co/guide/en/elasticsearch/client/python-api/current/index.html">Elasticsearch Python Client</a> to connect to your stack and validate queries.</p>
<pre><code>from elasticsearch import Elasticsearch
client = Elasticsearch(...)
data = {
"query": """
    from logs-endpoint.events.*
    | keep host.os.type, process.name, process.working_directory, event.type, event.action
    | where host.os.type == "linux" and process.name == "unshadow" and event.type == "start"     and event.action in ("exec", "exec_event")
"""
}

# Execute the query
headers = {"Content-Type": "application/json", "Accept": "application/json"}
response = client.perform_request(
"POST", "/_query", params={"pretty": True}, headers=headers, body=data
)
</code></pre>
<h2 id="leveragethegrammar">Leverage the grammar</h2>
<p>One of the best parts of Elastic developing in the open is the <a href="https://github.com/elastic/elasticsearch/tree/main/x-pack/plugin/esql/src/main/antlr">antlr ES|QL grammar</a> is also available.  </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt284924a161e4a9e4/6a7d851ede2315e605fd4eb7/image5.png" alt="" /></p>
<p>If you’re comfortable with <a href="https://www.antlr.org">ANTLR</a>, you can also download the latest JAR to build a lexer and parser.</p>
<pre><code>pip install antlr4-tools # for antlr4
git clone git@github.com:elastic/elasticsearch.git # large repo
cd elasticsearch/x-pack/plugin/esql/src/main/antlr # navigate to grammar
antlr4 -Dlanguage=Python3 -o build EsqlBaseLexer.g4 # generate lexer
antlr4 -Dlanguage=Python3 -o build EsqlBaseParser.g4 # generate parser
</code></pre>
<p>This process will require more lifting to get ES|QL validation started, but you’ll at least have a tree object built, that provides more granular control and access to the parsed fields.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8f8ca31d610c4958/6a7d8522ea068d11fef0728e/image13.png" alt="" /></p>
<p>However, as you can see the listeners are stubs, which means you’ll need to build in semantics <em>manually</em> if you want to go this route.</p>
<h2 id="thesecurityrulegithubciusecase">The security rule GitHub CI use case</h2>
<p>For our internal Elastic EQL and KQL query rule validation, we utilize the parsed abstract syntax tree (AST) objects of our queries to perform nuanced semantic validation across multiple stack versions. For example, having the AST allows us to validate proper field usage, verify new features are not used in older stack versions before being introduced, or even more, ensure related integrations are built based on datastreams used in the query. Fundamentally, local validation allows us to streamline a broader range of support for many stack features and versions. If you’re interested in seeing more of the design and rigorous validation that we can do with the AST, check out our <a href="https://github.com/elastic/detection-rules/tree/main">detection-rules repo</a>.</p>
<p>If you do not need granular access to the specific parsed tree objects and do not need to control the semantics of ES|QL validation, then out-of-the-box APIs may be all you need to validate queries. In this use case, we want to validate security detection rules using continuous integration. Managing detection rules through systems like GitHub helps garner all the benefits of using a version-controlled like tracking rule changes, receiving feedback via pull requests, and more. Conceptually, rule authors should be able to create these rules (which contain ES|QL queries) locally and exercise the git rule development lifecycle. </p>
<p>CI checks help to ensure queries still pass ES|QL validation without having to manually check the query in the UI. Based on the examples shown thus far, you have to either stand up a persistent stack and validate queries against the API, or build a parser implementation based on the available grammar outside of the Elastic stack. </p>
<p>One approach to using a short-lived Elastic stack versus leveraging a managed persistent stack is to use the <a href="https://github.com/peasead/elastic-container">Elastic Container Project (ECP)</a>. As advertised, this project will: </p>
<p><em>Stand up a 100% containerized Elastic stack, TLS secured, with Elasticsearch, Kibana, Fleet, and the Detection Engine all pre-configured, enabled, and ready to use, within minutes.</em></p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltaae300d8b34dcd81/6a7d852442a117b3bc9591a0/image11.png" alt="" /></p>
<p>With a combination of: </p>
<ul>
<li>Elastic Containers (e.g. ECP)</li>
<li>CI (e.g. Github Action Workflow)</li>
<li>ES|QL rules</li>
<li>Automation Foo (e.g. python &amp; bash scripts)</li>
</ul>
<p>You can validate ES|QL rules via CI against the <em>latest stack version</em> relatively easily, but there are some nuances involved in this approach.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf7ab06aa98ee1433/6a7d852973d9bd191f29ac8a/image2.gif" alt="" /></p>
<p>Feel free to check out the sample <a href="https://gist.github.com/Mikaayenson/7fa8f908ab7e8466178679a9a0cd9ecc">GitHub action workflow</a> if you’re interested in a high-level overview of how it can be implemented.</p>
<p><strong>Note:</strong> if you're interested in using the GitHub action workflow, check out their documentation on using GitHub <a href="https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions">secrets in Actions</a> and <a href="https://docs.github.com/en/actions/quickstart">setting up Action workflows</a>.</p>
<h2 id="cinuances">CI nuances</h2>
<ol>
<li>Any custom configuration needs to be scripted away (e.g. setting up additional policies, <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/match-enrich-policy-type.html">enrichments</a>, etc.) In our POC, we created a step and bash script that executed a series of POST requests to our temporary CI Elastic Stack, which created the new enrichments used in our detection rules.</li>
</ol>
<pre><code>- name: Add Enrich Policy
  env:
    ELASTICSEARCH_SERVER: "https://localhost:9200"
    ELASTICSEARCH_USERNAME: "elastic"
    ELASTICSEARCH_PASSWORD: "${{ secrets.PASSWORD }}"
  run: |
    set -x
    chmod +x ./add_enrich.sh
    bash ./add_enrich.sh
</code></pre>
<ol>
<li><p>Without data in our freshly deployed CI Elastic stack, there will be many <code>Unknown Column</code> issues as previously mentioned. One approach to address this is to build indices with the proper mappings for the queries to match. For example, if you have a query that searches the index <code>logs-endpoint.events.*</code>, then create an index called <code>logs-endpoint.events.ci</code>, with the proper mappings from the integration used in the query.  </p></li>
<li><p>Once the temporary stack is configured, you’ll need extra logic to iterate over all the rules and validate using the <code>_query</code> API. For example, you can create a unit test that iterates over all the rules. We do this today by leveraging our default <code>RuleCollection.default()</code> that loads all rules, in our detection-rules repo, but here is a snippet that quickly loads only ES|QL rules.</p></li>
</ol>
<pre><code># tests/test_all_rules.py
class TestESQLRules:
    """Test ESQL Rules."""

    @unittest.skipIf(not os.environ.get("DR_VALIDATE_ESQL"),
         "Test only run when DR_VALIDATE_ESQL environment variable set.")
    def test_environment_variables_set(self):
        collection = RuleCollection()

        # Iterate over all .toml files in the given directory recursively
        for rule in Path(DEFAULT_RULES_DIR).rglob('*.toml'):
            # Read file content
            content = rule.read_text(encoding='utf-8')
            # Search for the pattern
            if re.search(r'language = "esql"', content):
                print(f"Validating {str(rule)}")
                collection.load_file(rule)
</code></pre>
<p>Each rule would run through a validator method once the file is loaded with <code>load_file</code>. </p>
<pre><code># detection_rules/rule_validator.py
class ESQLValidator(QueryValidator):
    """Specific fields for ESQL query event types."""

    def validate(self, data: 'QueryRuleData', meta: RuleMeta) -&gt; None:
        """Validate an ESQL query while checking TOMLRule."""
        if not os.environ.get("DR_VALIDATE_ESQL"):
            return

        if Version.parse(meta.min_stack_version) &lt; Version.parse("8.11.0"):
            raise ValidationError(f"Rule minstack must be greater than 8.10.0 {data.rule_id}")

        client = Elasticsearch(...)
        client.info()
        client.perform_request("POST", "/_query", params={"pretty": True},
                               headers={"accept": "application/json", 
                                        "content-type": "application/json"},
                               body={"query": f"{self.query} | LIMIT 0"})
</code></pre>
<p>As highlighted earlier, we can <code>POST</code> to the query API and validate given the credentials that were set as GitHub action secrets and passed to the validation as environment variables.  Note, the <code>LIMIT 0</code> is so the query does not return data intentionally. It’s meant to only perform validation.  Finally the single CI step would be a bash call to run the unit tests (e.g. <code>pytest tests/test_all_rules.py::TestESQLRules</code>). </p>
<ol>
<li>Finally, CI leveraging containers may not scale well when validating many rules against multiple Elastic stack versions and configurations. Especially if you would like to test on a commit-basis. The time to deploy one stack took slightly over five minutes to complete. This measurement could greatly increase or decrease depending on your CI setup.   </li>
</ol>
<h2 id="conclusion">Conclusion</h2>
<p>Elasticsearch's new feature, Elasticsearch Query Language (ES|QL), is a specialized query and compute engine for Elasticsearch, now in technical preview. It offers seamless integration across various Elastic services like Kibana and Timelines, with validation options for ES|QL queries. Users can validate queries through the Elastic Stack UI or API calls, receiving immediate feedback on syntax or column errors. </p>
<p>Additionally, ES|QL's ANTLR grammar is <a href="https://github.com/elastic/elasticsearch/tree/d5f5d0908ff7d1bfb3978e4c57aa6ff517f6ed29/x-pack/plugin/esql/src/main/antlr">available</a> for those who prefer a more hands-on approach to building lexers and parsers. We’re exploring ways to validate ES|QL queries in an automated fashion and now it’s your turn. Just know that we’re not done exploring, so check out ES|QL and let us know if you have ideas! We’d love to hear how you plan to use it within the stack natively or in CI.</p>
<p>We’re always interested in hearing use cases and workflows like these, so as always, reach out to us via <a href="https://github.com/elastic/detection-rules/issues">GitHub issues</a>, chat with us in our <a href="http://ela.st/slack">community Slack</a>, and ask questions in our <a href="https://discuss.elastic.co/c/security/endpoint-security/80">Discuss forums</a>.</p>
<p>Check out these additional resources to learn more about how we’re bringing the latest AI capabilities to the hands of the analyst:
Learn everything <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql.html">ES|QL</a> 
Checkout the 8.11.0 release blog <a href="https://www.elastic.co/blog/whats-new-elasticsearch-platform-8-11-0">introducing ES|QL</a></p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/streamlining-esql-query-and-rule-validation</link>
    <guid isPermaLink="false">streamlining-esql-query-and-rule-validation</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Mika Ayenson,Eric Forte]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt387b552a76a75d4e/6a7d852ce02fac880a5d3574/photo-edited-01.png" length="0" type="image/png"/>
    <pubDate>Fri, 17 Nov 2023 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Unpacking ICEDID]]></title>
    <description><![CDATA[ICEDID is known to pack its payloads using custom file formats and a custom encryption scheme. We are releasing a set of tools to automate the unpacking process and help analysts and the community respond to ICEDID.]]></description>
    <content:encoded><![CDATA[<h2 id="preamble">Preamble</h2>
<p>ICEDID is a malware family <a href="https://securityintelligence.com/new-banking-trojan-icedid-discovered-by-ibm-x-force-research/">discovered</a>in 2017 by IBM X-force researchers and is associated with the theft of login credentials, banking information, and other personal information. ICEDID has always been a prevalent family but achieved even more growth since EMOTET’s temporary <a href="https://www.justice.gov/opa/pr/emotet-botnet-disrupted-international-cyber-operation">disruption</a> in early 2021. ICEDID has been linked to the distribution of several distinct malware families including <a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.darkvnc">DarkVNC</a> and <a href="https://www.cybereason.com/blog/threat-analysis-report-all-paths-lead-to-cobalt-strike-icedid-emotet-and-qbot">COBALT STRIKE</a>. Regular industry reporting, including research publications like this one, help mitigate this threat.</p>
<p>ICEDID is known to pack its payloads using custom file formats and a custom encryption scheme. Following our latest <a href="https://www.elastic.co/security-labs/thawing-the-permafrost-of-icedid-summary">ICEDID research</a> that covers the GZip variant execution chain.</p>
<p>In this tutorial, we will introduce these tools by unpacking a recent ICEDID sample starting with downloading a copy of the fake GZip binary:</p>
<p><strong>Analyzing malware can be dangerous to systems and should only be attempted by experienced professionals in a controlled environment, like an isolated virtual machine or analysis sandbox. Malware can be designed to evade detection and infect other systems, so it's important to take all necessary precautions and use specialized tools to protect yourself and your systems.</strong></p>
<p><a href="https://bazaar.abuse.ch/sample/54d064799115f302a66220b3d0920c1158608a5ba76277666c4ac532b53e855f/"><strong>54d064799115f302a66220b3d0920c1158608a5ba76277666c4ac532b53e855f</strong></a></p>
<h2 id="environmentsetup">Environment setup</h2>
<p>For this tutorial, we’re using Windows 10 and Python 3.10.</p>
<p>Elastic Security Labs is releasing a set of tools to automate the unpacking process and help analysts and the community respond to ICEDID.</p>
<p>| Script                                    | Description                                                      | Compatibility                   |
| ----------------------------------------- | ---------------------------------------------------------------- | ------------------------------- |
| decrypt_file.py                           | Decrypt ICEDID encrypted file                                    | Windows and others (not tested) |
| gzip_variant/extract_gzip.py              | Extract payloads from ICEDID fake GZip file                      | Windows and others (not tested) |
| gzip_variant/extract_payload_from_core.py | Extract and decrypt payloads from the rebuilt ICEDID core binary | Windows and others (not tested) |
| gzip_variant/load_core.py                 | Load and execute core custom PE binary                           | Windows only                    |
| gzip_variant/read_configuration.py        | Read ICEDID configuration file contained in the fake GZip        | Windows and others (not tested) |
| rebuild_pe.py                             | Rebuild a PE from ICEDID custom PE file                          | Windows and others (not tested) |</p>
<p>In order to use the tools, clone the <a href="https://github.com/elastic/labs-releases">Elastic Security Lab release repository</a> and install the nightMARE module.</p>
<pre><code>git clone https://github.com/elastic/labs-releases
cd labs-release
pip install .\nightMARE\
</code></pre>
<blockquote>
  <p>All tools in this tutorial use the <strong>nightMARE</strong> module, this library implements different algorithms we need for unpacking the various payloads embedded within ICEDID. We’re releasing nightMARE because it is required for this ICEDID analysis, but stay tuned - more to come as we continue to develop and mature this framework.</p>
</blockquote>
<h2 id="unpackingthefakegzip">Unpacking the fake GZip</h2>
<p>The ICEDID fake GZip is a file that <a href="https://attack.mitre.org/techniques/T1036/008/">masquerades</a> as a valid GZip file formatted by encapsulating the real data with a <a href="https://docs.fileformat.com/compression/gz/">GZip header and footer</a>.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt50ddb4d7b995e874/6a7d8652ead8ecbc8eba7bd6/image20.jpg" alt="GZip header and footer" title="GZip header and footer" /></p>
<p>GZip magic bytes appear in red.<br />
The GZip header is rendered in green.<br />
The dummy filename value is blue.</p>
<p>After the GZip header is the true data structure, which we describe below.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9275c738576801c2/6a7d8654bd2198e0d975536a/image19.jpg" alt="FakeGzip data structure" title="FakeGzip data structure" /></p>
<p>We will use the <strong>labs-releases\tools\icedid\gzip-variant\extract_gzip.py</strong> script to unpack this fraudulent GZip.</p>
<pre><code>usage: extract_gzip.py [--help] input output

positional arguments:
  input       Input file
  output      Output directory

options:
  -h, --help  show this help message and exit
</code></pre>
<p>We'll use extract_gzip.py on the ICEDID sample linked above and store the contents into a folder we created called “ <strong>extract</strong> ” (you can use any existing output folder).</p>
<pre><code>python extract_gzip.py 54d064799115f302a66220b3d0920c1158608a5ba76277666c4ac532b53e855f extract

============================================================
Fake Gzip
============================================================
is_dll: True
core: UponBetter/license.dat (354282 bytes)
stage_2: lake_x32.tmp (292352 bytes)

extract\configuration.bin
extract\license.dat
extract\lake_x32.tmp
</code></pre>
<p>This script returns three individual files consisting of:</p>
<ul>
<li>The encrypted configuration file: <strong>configuration.bin</strong></li>
<li>The encrypted core binary: <strong>license.dat</strong></li>
<li>The persistence loader: <strong>lake_x32.tmp</strong></li>
</ul>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1b21bb8542332618/6a7d86573cab1c6c480e1a98/image11.jpg" alt="Files extracted from the fake GZip" title="Files extracted from the fake GZip" /></p>
<h2 id="decryptingthecorebinaryandconfigurationfiles">Decrypting the core binary and configuration files</h2>
<p>The configuration and the core binary we extracted are encrypted using ICEDID’s custom encryption scheme. We can decrypt them with the <strong>labs-releases\tools\icedid\decrypt_file.py</strong> script.</p>
<pre><code>usage: decompress_file.py [--help] input output

positional arguments:
  input       Input file
  output      Output file

options:
  -h, --help  show this help message and exit
</code></pre>
<p>As depicted here (note that decrypted files can be written to any valid destination):</p>
<pre><code>python .\decrypt_file.py .\extract\license.dat .\extract\license.dat.decrypted

python .\decrypt_file.py .\extract\configuration.bin .\extract\configuration.bin.decrypted
</code></pre>
<p>The core binary and the configuration are now ready to be processed by additional tools. See the data from the decrypted configuration presented in the following screenshot:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt73b7ac96dd8477ab/6a7d865ae3a219bc6499c7aa/image17.jpg" alt="Hex view of the decrypted configuration file" title="Hex view of the decrypted configuration file" /></p>
<h2 id="readingtheconfiguration">Reading the configuration</h2>
<p>The configuration file format is presented below.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt83b12d9d68ffe9ad/6a7d865c6693f815ea661122/image4.png" alt="Configuration file" title="Configuration file" /></p>
<p>The configuration can be read using the <strong>labs-releases\tools\icedid\gzip-variant\read_configuration.py</strong> script.</p>
<pre><code>usage: read_configuration.py [--help] input

positional arguments:
  input       Input file

options:
  -h, --help  show this help message and exit
</code></pre>
<p>We’ll use the <strong>read_configuration.py</strong> script to read the <strong>configuration.bin.decrypted</strong> file we collected in the previous step.</p>
<pre><code>python .\gzip-variant\read_configuration.py .\extract\configuration.bin.decrypted

============================================================
Configuration
============================================================
botnet_id: 0x3B7D6BA4
auth_var: 0x00000038
uri: /news/
domains:
        alishaskainz.com
        villageskaier.com
</code></pre>
<p>This configuration contains two C2 domains:</p>
<ul>
<li>alishaskainz[.]com</li>
<li>villageskaier[.]com</li>
</ul>
<p>For this sample, the beaconing URI that ICEDID uses is “ <strong>/news/</strong> ”.</p>
<h2 id="rebuildingthecorebinaryforstaticanalysis">Rebuilding the core binary for static analysis</h2>
<p>ICEDID uses a custom PE format to obfuscate its payloads thus defeating static or dynamic analysis tools that expect to deal with a normal Windows executable. The custom PE file format is described below.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt04922004cf1df2bd/6a7d865f3cab1c57a30e1a9c/image8.jpg" alt="Custom PE file format" title="Custom PE file format" /></p>
<p>If we want to analyze the core binary, for example with <a href="https://hex-rays.com/IDA-pro/">IDA Pro</a>, we need to rebuild it into a valid PE. We use the <strong>labs-releases\tools\icedid\rebuild_pe.py</strong> script.</p>
<pre><code>usage: rebuild_pe.py [--help] [-o OFFSET] input output

positional arguments:
  input                 Input file
  output                Output reconstructed PE

options:
  -h, --help            show this help message and exit
  -o OFFSET, --offset OFFSET
                        Offset to real data, skip possible garbage
</code></pre>
<p>However, when attempting to use <strong>rebuild_pe.py</strong> on the decrypted core binary, <strong>license.dat.decrypted</strong> , we receive the following error message:</p>
<pre><code>python .\rebuild_pe.py .\extract\license.dat.decrypted .\extract\core.bin
Traceback (most recent call last):
  File "rebuild_pe.py", line 32, in &lt;module&gt;
    main()
  File "rebuild_pe.py", line 28, in main
    custom_pe.CustomPE(data).to_pe().write(args.output)
  File "nightmare\malware\icedid\custom_pe.py", line 86, in __init__
    raise RuntimeError("Failed to parse custom pe")
RuntimeError: Failed to parse custom pe
</code></pre>
<p>The subtlety here is that the custom PE data doesn’t always start at the beginning of the file. In this case, for example, if we open the file in a hexadecimal editor like <a href="https://mh-nexus.de/en/hxd/">HxD</a> we can observe a certain amount of garbage bytes before the actual data.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta28ab0488aeaa30e/6a7d8662fc63ab1fef64a04c/image14.jpg" alt="Prepended garbage bytes" title="Prepended garbage bytes" /></p>
<p>We know from our research that the size of the garbage is <strong>129</strong> bytes.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbf8c647dd18480b2/6a7d866577b03431783fc6f9/image1.jpg" alt="Identifying garbage size" title="Identifying garbage size" /></p>
<p>With that in mind, we can skip over the garbage bytes and rebuild the core binary using the <strong>rebuild_pe.py</strong> script using the <strong>“-o 129”</strong> parameter. This time we, fortunately, receive no error message. <strong>core.bin</strong> will be saved to the output directory, <strong>extract</strong> in our example.</p>
<pre><code>python .\rebuild_pe.py .\extract\license.dat.decrypted .\extract\core.bin -o 129
</code></pre>
<p>The rebuilt PE object is <strong>not</strong> directly executable but you can statically analyze it using your disassembler of choice.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltba667a144878d3db/6a7d8667448e4ed77b5bdbd0/image5.jpg" alt="IDA view of core.bin" title="IDA view of core.bin" /></p>
<p>We assigned custom names to the rebuilt binary sections ( <strong>.mare{0,1,2,…}</strong> ).</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf063caf74f457842/6a7d866add26d290f32a72db/image7.jpg" alt="Rebuilt binary section names" title="Rebuilt binary section names" /></p>
<p>We want to credit and thank <a href="https://github.com/hasherezade/funky_malware_formats/blob/f1cacba4ee347601dceacda04e4de8c699971d29/iced_id_parser/iceid_to_pe.cpp#L10">Hasherezade’s work</a> from which we took inspiration to build this tool.</p>
<h2 id="executingthecorebinarywindowsonly">Executing the core binary (Windows only)</h2>
<p>The core binary can’t be executed without a custom loader that understands ICEDID’s custom PE format as well as the entry point function prototype.</p>
<p>From our research, we know that the entry point expects a structure we refer to as the context structure, which contains ICEDID core and persistence loader paths with its encrypted configuration. The context structure is described below.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltda90856c4eee89fe/6a7d866db437705d734d401a/image2.jpg" alt="Context structure" title="Context structure" /></p>
<p>To natively execute the core binary we use the <strong>labs-releases\tools\icedid\gzip-variant\load_core.py</strong> script, but before using it we need to create the <strong>context.json</strong> file that’ll contain all the information needed by this script to build this structure.</p>
<p>For this sample, we copy the information contained in the fake gzip and we use the path to the encrypted configuration file. We’ve included an example at <strong>gzip_variant/context.json.example</strong>.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt84a496cf6500cec8/6a7d8670227b1c5d9c5958b2/image3.jpg" alt="Example configuration file" title="Example configuration file" /></p>
<p>Please note that <strong>“field_0”</strong> and <strong>“stage_2_export”</strong> values have to be found while reversing the sample.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt84cd01786bc4e2d1/6a7d86726693f83611661128/image16.jpg" alt="Populating values from previous research" title="Populating values from previous research" /></p>
<p>Here we use values from our previous research as placeholders but we have no guarantee that the sample will work 100%. For example, in this sample, we don’t know if the <strong>#1</strong> ordinal export is the actual entry point of the persistence loader.</p>
<p>We also reproduce the first stage behavior by creating the <strong>UponBetter</strong> directory and moving the <strong>license.dat</strong> file into it.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc93235d6dff17b6e/6a7d8675bd2198c6a9755372/image18.jpg" alt="license.dat in the UponBetter directory" title="license.dat in the UponBetter directory" /></p>
<p>We execute the <strong>labs-releases\tools\icedid\gzip_variant\load_core.py</strong> script using the <strong>decrypted core</strong> binary: <strong>license.dat.decrypted</strong> , the <strong>context.json</strong> file.</p>
<p><strong>WARNING: The binary is going to be loaded/executed natively by this script, Elastic Security Labs does not take responsibility for any damage to your system. Please execute only within a safe environment.</strong></p>
<pre><code>usage: load_core.py [--help] [-o OFFSET] core_path ctx_path

positional arguments:
  core_path             Core custom PE
  ctx_path              Path to json file defining core's context

options:
  -h, --help            show this help message and exit
  -o OFFSET, --offset OFFSET
                        Offset to real data, skip possible garbage
</code></pre>
<p>Because we have the same garbage bytes problem as stated in the previous section, we use the <strong>“-o 129”</strong> parameter to skip over the garbage bytes.</p>
<pre><code>python .\gzip-variant\load_core.py .\extract\license.dat.decrypted .\gzip-variant\context.example.json -o 129

============================================================
Core Loader
============================================================
Base address: 0x180000000
Entrypoint: 0x180001390

Press a key to call entrypoint...
</code></pre>
<p>When launched, the script will wait for user input before calling the entry point. We can easily attach a debugger to the Python process and set a breakpoint on the ICEDID core entry point (in this example <strong>0x180001390</strong> ).</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc2506f66989224e7/6a7d8678ead8ec5b18ba7bda/image13.jpg" alt="Breakpoint set on the ICEDID core entry point" title="Breakpoint set on the ICEDID core entry point" /></p>
<p>Once the key is pressed, we reach the entry point.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcc9b028fe3ea1e6d/6a7d867bbd2198af4d755376/image15.jpg" alt="ICEDID entry point" title="ICEDID entry point" /></p>
<p>If we let the binary execute, we see ICEDID threads being created (indicated in the following screenshot).</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt75b7936a91655474/6a7d867ddd26d268d32a72e1/image6.jpg" alt="ICEDID threads being created" title="ICEDID threads being created" /></p>
<h2 id="unpackingandrebuildingpayloadsfromtherebuiltcorebinary">Unpacking and rebuilding payloads from the rebuilt core binary</h2>
<p>For extracting any of the payloads that are embedded inside the core binary, we will use the <strong>labs-releases\tools\icedid\gzip-variant\extract_payloads_from_core.py</strong> script</p>
<pre><code>usage: extract_payloads_from_core.py [--help] input output

positional arguments:
  input       Input file
  output      Output directory

options:
  -h, --help  show this help message and exit
</code></pre>
<p>We’ll use this script on the rebuilt core binary.</p>
<pre><code>python .\gzip-variant\extract_payloads_from_core.py .\extract\core.bin core_extract

core_extract\browser_hook_payload_0.cpe
core_extract\browser_hook_payload_1.cpe
</code></pre>
<p>From here, we output two binaries corresponding to ICEDID’s payloads for web browser hooking capabilities, however, they are still in their custom PE format.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt77ca1275df57d0e6/6a7d8680de23155aa4fd4edf/image10.jpg" alt="ICEDID payloads" title="ICEDID payloads" /></p>
<p>Based on our research, we know that <strong>browser_hook_payload_0.cpe</strong> is the x64 version of the browser hook payload and <strong>browser_hook_payload_1.cpe</strong> is the x86 version.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt32c73c7818d9bcab/6a7d8683dd26d282312a72e5/image12.jpg" alt="Browser hook payload architectures" title="Browser hook payload architectures" /></p>
<p>In order to rebuild them, we use the <strong>rebuild_pe.py</strong> script again, this time there are no garbage bytes to skip over.</p>
<pre><code>python .\rebuild_pe.py .\core_extract\browser_hook_payload_0.cpe .\core_extract\browser_hook_payload_0.bin

python .\rebuild_pe.py .\core_extract\browser_hook_payload_1.cpe .\core_extract\browser_hook_payload_1.bin
</code></pre>
<p>Now we have two PE binaries ( <strong>browser_hook_payload_0.bin</strong> and <strong>browser_hook_payload_1.bin</strong> ) we can further analyze.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0217f341d3bcb975/6a7d868663e959247c73af3b/image9.jpg" alt="Payloads for further analysis" title="Payloads for further analysis" /></p>
<p>Attentive readers may observe that we have skipped the <strong>VNC server</strong> unpacking from the core binary, a decision we made intentionally. We will release it along with other tools in upcoming research, so stay tuned!</p>
<h2 id="conclusion">Conclusion</h2>
<p>In this tutorial we covered ICEDID GZip variant unpacking, starting with the extraction of the fake GZip binary, followed by the reconstruction of the core binary and unpacking its payloads.</p>
<p>ICEDID is constantly evolving, and we are going to continue to monitor major changes and update our tooling along with our research. Feel free to <a href="https://github.com/elastic/labs-releases/issues">open an issue</a> or <a href="mailto:threat-notification@elastic.co">send us a message</a> if something is broken or doesn’t work as expected.</p>
<p>Elastic Security Labs is a team of dedicated researchers and security engineers focused on disrupting adversaries through the publication of detailed detection logic, protections, and applied threat research.</p>
<p>Follow us on <a href="https://twitter.com/elasticseclabs">@elasticseclabs</a>and visit our research portal for more resources and research.</p>
<h2 id="references">References</h2>
<p>The following were referenced throughout the above research:</p>
<ul>
<li><a href="https://www.elastic.co/pdf/elastic-security-labs-thawing-the-permafrost-of-icedid.pdf">https://www.elastic.co/pdf/elastic-security-labs-thawing-the-permafrost-of-icedid.pdf</a></li>
<li><a href="https://securityintelligence.com/new-banking-trojan-icedid-discovered-by-ibm-x-force-research/">https://securityintelligence.com/new-banking-trojan-icedid-discovered-by-ibm-x-force-research/</a></li>
<li><a href="https://www.justice.gov/opa/pr/emotet-botnet-disrupted-international-cyber-operation">https://www.justice.gov/opa/pr/emotet-botnet-disrupted-international-cyber-operation</a></li>
<li><a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.darkvnc">https://malpedia.caad.fkie.fraunhofer.de/details/win.darkvnc</a></li>
<li><a href="https://www.cybereason.com/blog/threat-analysis-report-all-paths-lead-to-cobalt-strike-icedid-emotet-and-qbot">https://www.cybereason.com/blog/threat-analysis-report-all-paths-lead-to-cobalt-strike-icedid-emotet-and-qbot</a></li>
<li><a href="https://github.com/elastic/labs-releases">https://github.com/elastic/labs-releases</a></li>
<li><a href="https://github.com/hasherezade/funky_malware_formats/blob/f1cacba4ee347601dceacda04e4de8c699971d29/iced_id_parser/iceid_to_pe.cpp">https://github.com/hasherezade/funky_malware_formats/blob/f1cacba4ee347601dceacda04e4de8c699971d29/iced_id_parser/iceid_to_pe.cpp</a></li>
<li><a href="https://mh-nexus.de/en/hxd/">https://mh-nexus.de/en/hxd/</a></li>
<li><a href="https://hex-rays.com/IDA-pro/">https://hex-rays.com/IDA-pro/</a></li>
</ul>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/unpacking-icedid</link>
    <guid isPermaLink="false">unpacking-icedid</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Cyril François]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltff767be2885aaad8/6a7d8689c2e9144da4013d43/photo-edited-07@2x.jpg" length="0" type="image/jpeg"/>
    <pubDate>Thu, 04 May 2023 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Click, Click… Boom! Automating Protections Testing with Detonate]]></title>
    <description><![CDATA[To automate this process and test our protections at scale, we built Detonate, a system that is used by security research engineers to measure the efficacy of our Elastic Security solution in an automated fashion.]]></description>
    <content:encoded><![CDATA[<h2 id="preamble">Preamble</h2>
<p>Imagine you are an Endpoint artifact developer. After you put in the work to ensure protection against conventional shellcode injections or ransomware innovations, how do you know it actually works before you send it out into the world?</p>
<p>First, you set up your end-to-end system, which involves setting up several services, the infrastructure, network configuration, and more. Then, you run some malware; the data you collect answers questions about performance and efficacy, and may be an important research resource in the future. After you spend a day testing and gathering your results, you may want to run several hundred hashes over multiple kinds of operating systems and machine types, a daunting task if done entirely manually.</p>
<p>To automate this process and test our protections at scale, we built Detonate, a system that is used by security research engineers to measure the efficacy of our Elastic Security solution in an automated fashion. Our goal is to have it take security researchers only a couple of clicks to test our protections against malware. (Thus: click, click… boom!)</p>
<p>In this series of posts, we’ll: - Introduce Detonate and why we built it - Explore how Detonate works and the technical implementation details - Describe case studies on how our teams use it at Elastic - Discuss opening our efficacy testing to the community to help the world protect their data from attack</p>
<p>Interested in other posts on Detonate? Check out <a href="https://www.elastic.co/security-labs/into-the-weeds-how-we-run-detonate">Part 2 - Into The Weeds: How We Run Detonate</a> where we break down how Detonate works and dive deeper into the technical implementation.</p>
<h2 id="whatisdetonate">What is Detonate?</h2>
<p>At a high level, Detonate runs malware and other potentially malicious software in a controlled (i.e., sandboxed) environment where the full suite of Elastic Security capabilities are enabled. Detonate accepts a file hash (usually a SHA256) and performs the following actions:</p>
<ul>
<li>Prepares all files needed for detonation, including the malicious file</li>
<li>Provisions a virtual machine (VM) instance in a sandboxed environment, with limited connectivity to the outside world</li>
<li>Waits until file execution completes; this happens when, for example, an execution result file is found or the VM instance is stopped or older than a task timeout</li>
<li>Stops the running VM instance (if necessary) and cleans up the sandboxed environment</li>
<li>Generates an event summary based on telemetry and alerts produced during detonation</li>
</ul>
<p>The results of these detonations are made available to the team for research and development purposes. By post-processing the logs, events, and alerts collected during detonation, we can enrich them with third-party intelligence and other sources to evaluate the efficacy of new and existing Elastic Security protection features.</p>
<h2 id="whatdoesithelpuswith">What does it help us with?</h2>
<h3 id="measuringefficacy">Measuring Efficacy</h3>
<p>To build the best EPP on the market, we have to continuously measure the effectiveness of our product against the latest threats. Detonate is used to execute many tens of thousands of samples every month from our data feeds. Gaps in coverage are automatically identified and used to prioritize improvements to our protections.</p>
<h3 id="supportingexistingprotections">Supporting existing protections</h3>
<p>Many of our protections have associated artifacts (such as machine learning models and rule definitions) which receive regular updates. These updates need testing to ensure we identify and remediate regressions before they end up in a user’s environment.</p>
<p>Detonate provides a framework and suite of tools to automate the analysis involved in this testing process. By leveraging a corpus of hashes with known good and bad software, we can validate our protections before they are deployed to users.</p>
<h3 id="threatresearch">Threat research</h3>
<p>Some of our security researchers scour the internet daily for new and emerging threats. By giving them an easy-to-use platform to test malicious software they find in the wild, we better understand how Elastic Security defends against those threats or if we need to update our protections.</p>
<h3 id="evaluatingnewprotections">Evaluating new protections</h3>
<p>In addition to testing existing protections, new protections run the risk of adverse interactions with our existing suite of layered capabilities. A new protection may be easily tested on its own, but tests may hide unintended interactions or conflicts with existing protections. Detonate provides a way for us to customize the configuration of the Elastic Stack and individual protections to more easily find and identify such conflicts earlier in development.</p>
<h2 id="whatsnext">What’s next?</h2>
<p>In this publication, we introduced Detonate &amp; what we use it for at Elastic. We discussed the benefits it provides our team when assessing the performance of our security artifacts.</p>
<p>Now that you know what it is, we will break down how Detonate works. In our next post, we’ll dive deeper into the technical implementation of Detonate and how we’re able to create this sandboxed environment in practice.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/click-click-boom-automating-protections-testing-with-detonate</link>
    <guid isPermaLink="false">click-click-boom-automating-protections-testing-with-detonate</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Jessica David,Hez Carty,Sergey Polzunov]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt06b071bc67ede56d/6a7d7e1be3a2192f8799c697/blog-thumb-tools-various.jpg" length="0" type="image/jpeg"/>
    <pubDate>Thu, 04 May 2023 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[The Elastic Container Project for Security Research]]></title>
    <description><![CDATA[The Elastic Container Project provides a single shell script that will allow you to stand up and manage an entire Elastic Stack using Docker. This open source project enables rapid deployment for testing use cases.]]></description>
    <content:encoded><![CDATA[<h2 id="preamble">Preamble</h2>
<p>The Elastic Stack is a modular data analysis ecosystem. While this allows for engineering flexibility, it can be cumbersome to stand up a development instance for testing. The easiest way to stand up the Elastic Stack, is to use <a href="https://cloud.elastic.co">Elastic Cloud</a> - it’s completely turnkey. However, there could be situations where Elastic Cloud won’t work for your testing environment. To help with this, this blog will provide you with the necessary information required in order to quickly and painlessly stand up a local, fully containerized, TLS-secured, Elastic Stack with Fleet and the Detection Engine enabled. You will be able to create a Fleet policy, install an Elastic Agent on a local host or VM, and send the data into your stack for monitoring or analysis.</p>
<p>This blog will cover the following:</p>
<ul>
<li>The Elastic Stack</li>
<li>The Elastic Container project</li>
<li>How to use the Elastic Container project</li>
<li>How to navigate Kibana and use its related features for security research</li>
</ul>
<blockquote>
  <p>The Elastic Container Project is not sponsored or maintained by the company, Elastic. Design and implementation considerations for the project may not reflect Elastic’s guidance on deploying a production-ready stack.</p>
</blockquote>
<h2 id="theelasticstack">The Elastic Stack</h2>
<p>The Elastic Stack is made up of several different components, each of which provide a distinct capability that can be utilized across a wide variety of use cases.</p>
<h3 id="elasticsearch">Elasticsearch</h3>
<p>Elasticsearch is a distributed, RESTful search and analytics engine. As the heart of the Elastic Stack, it centrally stores your data for lightning-fast search, fine-tuned relevancy, and powerful analytics that scale with ease.</p>
<h3 id="kibana">Kibana</h3>
<p>Kibana is the user interface that lets you visualize your Elasticsearch data and manage the Elastic Stack.</p>
<h3 id="theelasticagent">The Elastic Agent</h3>
<p>The Elastic Agent is the modular agent that allows you to collect data from an endpoint or act as a vehicle to ship data from 3rd party sources, like threat feeds. The Elastic Security integration for endpoints prevents ransomware and malware, detects advanced threats, and arms responders with vital investigative context.</p>
<h2 id="theelasticcontainerproject">The Elastic Container Project</h2>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8c79097ab1ac1da1/6a7d85a048511bc342e7d3ef/elastic-container.png" alt="The Elastic Container Project" title="The Elastic Container Project" /></p>
<p>As mentioned above, the Elastic Stack is modular which makes it very flexible for a wide variety of use cases but this can add complexity to the implementation.</p>
<p>The Elastic Container project is an open source project that uses Docker Compose as a way to stand up a fully-functional Elastic Stack for use in non-production environments. This project is not sponsored or maintained by the Elastic company.</p>
<h3 id="introduction">Introduction</h3>
<p>The <a href="https://github.com/peasead/elastic-container">Elastic Container Project</a> includes three main components:</p>
<ul>
<li>Elasticsearch</li>
<li>Kibana</li>
<li>the Elastic Agent</li>
</ul>
<p>The project leverages <a href="https://docs.docker.com/compose/">Docker Compose</a>, which is a tool to build, integrate, and manage multiple Docker containers.</p>
<p>To simplify the management of the containers, the project includes a shell script that allows for the staging, starting, stopping, and destroying of the containers.</p>
<p>Additionally, the project makes use of self-signed TLS certificates between Elasticsearch and Kibana, Kibana and your web browser, the Elastic Agent and Elasticsearch, and the Elastic Agent and Kibana.</p>
<h3 id="prerequisites">Prerequisites</h3>
<p>The project was built and tested on Linux and macOS operating systems. If you are using Windows, you’ll not be able to use the included shell script, but you can still run native Docker Compose commands and manually perform post-deployment steps.</p>
<p>While not thoroughly tested, it is recommended that you contribute 4 cores and 8 GB of RAM to Docker.</p>
<p>There are only a few packages you need to install:</p>
<ul>
<li>Docker</li>
<li>Docker Compose</li>
<li>jq</li>
<li>Git</li>
<li>cURL</li>
</ul>
<h4 id="macos">macOS</h4>
<p>If you’re running on macOS, you can install the prerequisites using <a href="https://brew.sh/">Homebrew</a>, which is an open-source package management system for macOS. Check out the Homebrew site for information on installing it if needed.</p>
<pre><code>**brew install jq git**
**brew install --cask docker**
</code></pre>
<h4 id="linux">Linux</h4>
<p>If you’re running on Linux, you can install the prerequisites using your package management system ( <strong>DNF</strong> , <strong>Yum</strong> , or <strong>APT</strong> ).</p>
<p><strong>RPM-based distributions</strong></p>
<pre><code>**dnf install jq git curl**
</code></pre>
<p><strong>Ubuntu</strong></p>
<pre><code>**apt-get install jq git curl**
</code></pre>
<p>You'll also need the Docker suite (including the <strong>docker-compose-plugin</strong> ). Check out Docker's <a href="https://docs.docker.com/engine/install/">installation instructions</a> for your OS'</p>
<h3 id="cloningtheprojectrepository">Cloning the project repository</h3>
<p>The Elastic Container project is stored on Github. As long as you have Git installed, you can collect it from your CLI of choice.</p>
<pre><code>**git clone https://github.com/peasead/elastic-container.git**
**cd elastic-container**
</code></pre>
<p>This repository includes everything needed to stand up the Elastic Stack containers using a single shell script.</p>
<h3 id="settingcredentials">Setting credentials</h3>
<p>Before proceeding, ensure you update the credentials for the Elastic and Kibana accounts in the <strong>.env</strong> file located in the root directory of the repository from their defaults of <strong>changeme</strong>.</p>
<h3 id="theshellscript">The shell script</h3>
<p>As mentioned above, the project includes a shell script that will simplify the management of the containers.</p>
<pre><code>**usage: ./elastic-container.sh [-v] (stage|start|stop|restart|status|help)**
**actions:**
 **stage downloads all necessary images to local storage**
 **start creates network and starts containers**
 **stop stops running containers without removing them**
 **destroy stops and removes the containers, the network and volumes created**
 **restart simply restarts all the stack containers**
 **status check the status of the stack containers**
 **help print this message**
 **flags:**
 **-v enable verbose output**
</code></pre>
<h4 id="stage">Stage</h4>
<p>This option downloads all of the containers from the Elastic Docker hub. This is useful if you are going to be building the project on a system that does not always have Internet access. This is not required, you can skip this option and move directly to the start option, which will download the containers.</p>
<pre><code>**$ ./elastic-container.sh stage**
**8.3.0: Pulling from elasticsearch/elasticsearch**
**7aabcb84784a: Already exists**
**e3f44495617d: Downloading [====\\&gt;] 916.5kB/11.26MB**
**52008db3f842: Download complete**
**551b59c59fdc: Downloading [\\&gt;] 527.4kB/366.9MB**
**25ee26aa662e: Download complete**
**7a85d02d9264: Download complete**
**…**
</code></pre>
<h4 id="start">Start</h4>
<p>This opinion will create the container network, download all of the required containers, set up the TLS certificates, and start and connect Elasticsearch, Kibana, and the Fleet server containers together. This option is a “quick start” to get the Elastic Stack up and running. If you have not changed your credentials in the .env file from the defaults, the script will exit.</p>
<pre><code>**$ ./elastic-container.sh start**

**Starting Elastic Stack network and containers**
**[+] Running 7/8**
 **⠿ Network elastic-container\_default Created 0.0s**
 **⠿ Volume "elastic-container\_certs" Created 0.0s**
 **⠿ Volume "elastic-container\_esdata01" Created 0.0s**
 **⠿ Volume "elastic-container\_kibanadata" Created 0.0s**
 **⠿ Container elasticsearch-security-setup Waiting 2.0s**
 **⠿ Container elasticsearch Created 0.0s**
**…**
</code></pre>
<h4 id="stop">Stop</h4>
<p>This option will stop all running containers in the project, but will not remove them.</p>
<pre><code>**$ ./elastic-container.sh stop**

**Stopping running containers.**
**[+] Running 4/4**
 **⠿ Container elastic-agent Stopped 0.0s**
 **⠿ Container kibana Stopped 0.0s**
 **⠿ Container elasticsearch Stopped 0.0s**
 **⠿ Container elasticsearch-security-setup Stopped**
**…**
</code></pre>
<h4 id="destroy">Destroy</h4>
<p>This option will stop all running containers in the project, remove the container network, remove all data volumes, and remove all containers.</p>
<pre><code>**$ ./elastic-container.sh destroy**

**#####**
**Stopping and removing the containers, network, and volumes created.**
**#####**
**[+] Running 8/4**
 **⠿ Container elastic-agent Removed 0.0s**
 **⠿ Container kibana Removed 0.0s**
 **⠿ Container elasticsearch Removed 0.0s**
 **⠿ Container elasticsearch-security-setup Removed 0.3s**
 **⠿ Volume elastic-container\_esdata01 Removed 0.0s**
 **⠿ Network elastic-container\_default Removed 0.1s**
**…**
</code></pre>
<h4 id="restart">Restart</h4>
<p>This option restarts all of the project containers.</p>
<pre><code>**$ ./elastic-container.sh restart

#####
Restarting all Elastic Stack components.
#####
Name Command State Ports
---------------------------
elasticsearch /bin/tini -- /usr/local/bi ... Up (healthy) 0.0.0.0:9200-\\&gt;9200/tcp, 9300/tcp
fleet-server /usr/bin/tini -- /usr/loca ... Up 0.0.0.0:8220-\\&gt;8220/tcp
kibana /bin/tini -- /usr/local/bi ... Up (healthy) 0.0.0.0:5601-\\&gt;5601/tcp**
</code></pre>
<h4 id="status">Status</h4>
<p>This option returns the status of the project containers.</p>
<pre><code>**$ ./elastic-container.sh status**
**Name Command State Ports**
**---------------------------**
**elasticsearch /bin/tini -- /usr/local/bi ... Up (healthy) 0.0.0.0:9200-\\&gt;9200/tcp, 9300/tcp**
**fleet-server /usr/bin/tini -- /usr/loca ... Up 0.0.0.0:8220-\\&gt;8220/tcp**
**kibana /bin/tini -- /usr/local/bi ... Up (healthy) 0.0.0.0:5601-\\&gt;5601/tcp**
</code></pre>
<h4 id="clear">Clear</h4>
<p>This option clears all documents in the logs and metrics indices.</p>
<pre><code>**$ ./elastic-container.sh clear**

**Successfully cleared logs data stream**
**Successfully cleared metrics data stream**
</code></pre>
<h4 id="help">Help</h4>
<p>This option provides instructions on using the shell script.</p>
<pre><code>**$ ./elastic-container.sh help**

**usage: ./elastic-container.sh [-v] (stage|start|stop|restart|status|help)**
**actions:**
 **stage downloads all necessary images to local storage**
 **start creates a container network and starts containers**
 **stop stops running containers without removing them**
 **destroy stops and removes the containers, the network and volumes created**
 **restart simply restarts all the stack containers**
 **status check the status of the stack containers**
**clear all documents in logs and metrics indexes**
 **help print this message**
**flags:**
 **-v enable verbose output**
</code></pre>
<h2 id="gettingstarted">Getting Started</h2>
<p>Now that we’ve walked through the project overview and the shell script, let’s go through the process of standing up your own stack.</p>
<h3 id="updatingvariables">Updating variables</h3>
<p>All of the variables are controlled in an environment file ( <strong>.env</strong> ) that is at the root of the repository. The only things that you must change are the default usernames and passwords for <strong>elastic</strong> and <strong>kibana</strong>.</p>
<p>Open the <strong>.env</strong> file with whatever text editor you’re most comfortable with and update the <strong>ELASTIC_PASSWORD</strong> and <strong>KIBANA_PASSWORD</strong> variables from <strong>changeme</strong> to something secure. If you do not update the credentials from the defaults in the <strong>.env</strong> file, the script will exit.</p>
<p>If you want to change the other variables (such as the stack version), you can do so in this file.</p>
<h3 id="startingtheelasticstack">Starting the Elastic Stack</h3>
<p>Starting the project containers is as simple as running the <strong>elastic-container.sh</strong> shell script with the start option.</p>
<pre><code>**$ ./elastic-container.sh start**

**Starting Elastic Stack network and containers
[+] Running 7/8
⠿ Network elastic-container\_default Created 0.0s
⠿ Volume "elastic-container\_certs" Created 0.0s
⠿ Volume "elastic-container\_esdata01" Created 0.0s
⠿ Volume "elastic-container\_kibanadata" Created 0.0s
⠿ Container elasticsearch-security-setup Waiting 2.0s
⠿ Container elasticsearch Created 0.0s
⠿ Container kibana Created 0.1s
⠿ Container fleet-server Created 0.2s

Attempting to enable the Detection Engine and Prebuilt-Detection Rules
Kibana is up. Proceeding
Detection engine enabled. Installing prepackaged rules.
Prepackaged rules installed!
Waiting 40 seconds for Fleet Server setup
Populating Fleet Settings
READY SET GO!

Browse to https://localhost:5601
Username: elastic
Passphrase: you-changed-me-from-the-default-right?**
</code></pre>
<h3 id="accessingtheelasticstack">Accessing the Elastic Stack</h3>
<p>Once the containers have all downloaded and started, you’ll get an output that tells you to browse to <strong>https://localhost:5601</strong>.</p>
<p><strong>Note:</strong> You’ll need to accept the self-signed TLS certificate.</p>
<h2 id="enablingtheplatinumfeatures">Enabling the Platinum Features</h2>
<p>Enabling the Platinum license features are completely optional. Security features, like anti-malware, EDR, EPP, etc. are included in the Basic license. Memory, behavior, and ransomware protections are Platinum license features. If you want to change your license, we can do that with the <strong>.env</strong> file or from within Kibana. You can update to Elastic Platinum for 30-days.</p>
<p>If you want to use the <strong>.env</strong> file so that the features are enabled when the stack is built, change <strong>LICENSE=basic</strong> to <strong>LICENSE=trial</strong> and then start the project as normal.</p>
<p>If you prefer to use Kibana, click on the hamburger menu, and then click on Stack Management.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt376ce08a331b9101/6a7d85a35967e56e9b5da5bd/image5.jpg" alt="Access Stack Management from Kibana" title="Access Stack Management from Kibana" /></p>
<p>Click on License Management and then “Start a 30-day trial”.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt39b3267c18c07447/6a7d85a642a117cd839591ba/image24.png" alt="Start a 30-day trial" title="Start a 30-day trial" /></p>
<h2 id="creatingafleetpolicy">Creating a Fleet policy</h2>
<p>Now that we have the entire Elastic Stack up and running, we can make a <a href="https://www.elastic.co/guide/en/kibana/current/fleet.html">Fleet</a> policy. Fleet is a subroutine of an <a href="https://www.elastic.co/elastic-agent">Elastic Agent</a> (which was built when we ran the <strong>start</strong> option in the shell script) that enables you to manage other Elastic Agents, policies, and integrations.</p>
<blockquote>
  <p>Fleet is managed in Kibana, the UI that allows you to interact with data stored in Elasticsearch and manage your Elastic stack. If you’re interested in learning more about Kibana, check out the <a href="https://www.elastic.co/training/free#quick-starts">free</a> <a href="https://www.elastic.co/training/free#how-to">training</a> <a href="https://www.elastic.co/training/free#fundamentals">videos</a>.</p>
</blockquote>
<p>Log into your Kibana instance and click on the “hamburger” menu on the top left, and navigate down to “Fleet”, under the “Management” section.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf6895fcaf6265c88/6a7d85a948511bcbade7d3f3/image17.jpg" alt="Accessing Fleet" title="Accessing Fleet" /></p>
<p>Next, click on the “Agent policies” tab and then the “Create agent policy” button.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9f2e8511d2bb60dd/6a7d85ace02fac39305d3586/image27.png" alt="Create agent policy" title="Create agent policy" /></p>
<p>Give your new policy a name and a description (optional). Normally, we uncheck the “Collect agent logs” and “Collect agent metrics” options because it’s additional data going to the stack that we generally don’t need for our specific use-case. If you’re doing troubleshooting or interested in what’s happening behind the scenes, this data can help you understand that.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcfad070abd237f78/6a7d85af42a11772a19591be/Agent_policies_-_Fleet_-_Elastic.jpg" alt="Defining the agent policy" title="Defining the agent policy" /></p>
<p>Next, click on your new policy and the blue “Add integration” button.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3295ec795c5d7cde/6a7d85b2de231566bdfd4ec9/image15.png" alt="Open the Fleet policy" title="Open the Fleet policy" /></p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8b5f15e860dbc35b/6a7d85b577b03421143fc6d9/image3.jpg" alt="Add integrations" title="Add integrations" /></p>
<p>There are hundreds of integrations, but the ones that we’re most interested in for this blog are for Elastic Security.</p>
<p>To install Elastic Security, simply click on the tile on the main integrations page or search for “security”.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte3acf2acf70c94cb/6a7d85b877b03461403fc6df/image16.png" alt="Endpoint and Cloud Security integration" title="Endpoint and Cloud Security integration" /></p>
<p>Next, click the “Add Endpoint and Cloud Security” button to install this integration into the policy we just created.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt36c6d2fd99ece510/6a7d85bb227b1c6bda5958a2/image4.jpg" alt="Add Endpoint and Cloud Security" title="Add Endpoint and Cloud Security" /></p>
<p>Name the integration and click the blue “Save and continue” button.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt87bb2414a3d65ab0/6a7d85be6c6eac5f79f113ed/image1.jpg" alt="Save the integration to the policy" title="Save the integration to the policy" /></p>
<blockquote>
  <p>While the Endpoint and Cloud Security and System integrations will collect security related logs, if you’re using Sysmon on a Windows host, you may want to add the “Windows” integration to collect those logs.</p>
</blockquote>
<p>Once the integration is installed, you’ll be prompted to add more Agents or to do that later. Select the “Add Elastic Agent later” option so we can make a few more changes to our policy.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt61cb9c381ddc33d2/6a7d85c005b7b58129188bdf/image19.jpg" alt="Add Elastic Agents later" title="Add Elastic Agents later" /></p>
<p>Now we’ll be dropped back to our policy page.</p>
<p>We should have two integrations for our policy: <strong>security</strong> and <strong>system-1</strong>.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcfad070abd237f78/6a7d85af42a11772a19591be/Agent_policies_-_Fleet_-_Elastic.jpg" alt="Reviewing the Windows policy" title="Reviewing the Windows policy" /></p>
<p>Before we add any agents, we’ll want to set our Elastic Agent to Detect (so that it allows the malware to completely execute), register the Elastic Agent as a trusted AV solution (Windows only), and instruct the Endpoint and Cloud Security integration to collect memory samples from security events. This is tremendously helpful for “fileless” malware that injects directly into memory, like Cobalt Strike.</p>
<blockquote>
  <p>If you want to learn more about extracting malware beacons from events generated by the Elastic Agent, check out our other <a href="https://www.elastic.co/security-labs/collecting-cobalt-strike-beacons-with-the-elastic-stack">publications</a> and <a href="https://github.com/elastic/malware-exquacker">repositories</a>.</p>
</blockquote>
<p>To allow the malware to continue to execute, on your “Windows” policy page, click on the name of the integration (“security” in our example), set the Protection level to “Detect”.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt937eeefe7bd4c8ab/6a7d85c4dd26d2ca112a72cb/image25.jpg" alt="Setting the Protection level to Detect" title="Setting the Protection level to Detect" /></p>
<p>Repeat these steps for the Ransomware, Memory threat protections, and Malicious behavior sections.</p>
<blockquote>
  <p>We’re setting the Elastic Agent to Detect so that the malware we’re detonating will run completely so that we can analyze the entire execution chain. If you want the malware to be stopped, you can leave this in Prevent mode.</p>
</blockquote>
<p>Next, scroll to the bottom and select the “Register as antivirus” toggle and click on the “Show advanced settings” hyperlink.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte64c893d63f83c9d/6a7d85c742a117c4479591c6/image18.jpg" alt="Register as antivirus" title="Register as antivirus" /></p>
<p>Scroll down to <strong>windows.advanced.memory_protection.shellcode_collect_sample</strong> , <strong>windows.advanced.memory_protection.memory_scan_collect_sample</strong> , and <strong>windows.advanced.memory_protection.shellcode_enhanced_pe_parsing</strong> options and set the value to <strong>true</strong>.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt64f651ccb07e8e73/6a7d85c9e88c654a000089f2/image26.jpg" alt="Enabling sample collection" title="Enabling sample collection" /></p>
<blockquote>
  <p>As mentioned above, these steps are for labs, sandboxes, testing, etc. These settings can generate a lot of data, so setting these for production will need resourcing and sizing considerations.</p>
</blockquote>
<p>If you’re making a policy for Linux or macOS, repeat these for the proper OS.</p>
<p>Once we’re done with all of the post-installation configurations, we can click the blue Save integration button.</p>
<h2 id="enablingelasticsprebuiltdetectionrules">Enabling Elastic’s Prebuilt Detection Rules</h2>
<p>Now that we have created our Fleet agent policy we need to enable the set of pre-built detection rules associated with the OS or platform we will be deploying on (e.g Windows). To do this you will need to go to the Alerts page within the security app.</p>
<p>Click on the hamburger menu and select Alerts, under the Security solution.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd322dbffb153ec8a/6a7d85cce88c6519f30089f6/Home_-_Elastic.jpg" alt="Access the Alerts section" title="Access the Alerts section" /></p>
<p>Next, click on the blue Manage Rules button.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2edf0bfbec9199f1/6a7d85cf77b034dd513fc6e5/Alerts_-_Kibana.jpg" alt="Access the Manage rules interface" title="Access the Manage rules interface" /></p>
<p>Once on the Rules page you can update all of the prebuilt rules provided by Elastic by clicking on the “Update Elastic prebuilt rules” button. The update framework is enabled when you go into the “Manage rules” section for the first time, if the “Update Elastic prebuilt rules” button isn’t present, refresh the screen.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt84552bd2e669fb2a/6a7d85d233fa8a0ca31ffa02/Rules_-_Kibana.jpg" alt="Update Elastic prebuilt rules" title="Update Elastic prebuilt rules" /></p>
<p>Once the rules have been updated, you can browse the available detection rules, search them by a number of different patterns or simply filter by tag, which is what we will do here by searching for Windows rules.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc105fc922475f5c5/6a7d85d4bd2198a504755352/Rules_-_Kibana-2.jpg" alt="Filter for Windows rules" title="Filter for Windows rules" /></p>
<p>Now we can select all of the Windows rules.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt00e852d6576fa373/6a7d85d73cab1c62830e1a84/Rules_-_Kibana-3.jpg" alt="Selecting all Windows rules" title="Selecting all Windows rules" /></p>
<p>Once all of the rules have been selected, we can bulk enable them.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt10249aaca0e9738d/6a7d85da96b5a6c06e8786d1/Rules_-_Kibana-4.jpg" alt="Bulk enable Windows rules" title="Bulk enable Windows rules" /></p>
<blockquote>
  <p>As the Elastic Container Project runs completely inside single Docker containers, performance impacts could be noticed if you enable all of the rules available. Explore the different rules and enable or disable them based on your infrastructure and use cases.</p>
</blockquote>
<p>After we have enabled these rules they will be live and will be run against the data your endpoint agent sends into your stack. When the Detection Engine rules are triggered, they will be raised in the Alerts page in the Security Solution.</p>
<h2 id="enrollinganelasticagent">Enrolling an Elastic Agent</h2>
<p>Still in Fleet, we have several ways to add an Elastic Agent. The most straightforward is from within the policy that we want to enroll an Elastic Agent into (otherwise you have to specify which policy you want to use). It doesn’t really matter which approach you use, but clicking on the Actions button and then Add agent works from just about anywhere in Fleet.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc7bcb8dbaee23733/6a7d85dd3cab1c62850e1a88/image8.jpg" alt="Adding Elastic Agent" title="Adding Elastic Agent" /></p>
<p>Scroll down and click on the OS that you’re going to be installing the Elastic Agent on, and copy/paste the instructions directly into a terminal window on the host you’re going to be installing the agent onto. Note, if you’re using Windows, use a Powershell CLI that is running as (or elevated to) an account with administrative entitlements.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7d2ea5578694a586/6a7d85e048511b3499e7d405/image22.png" alt="Powershell commands to add an Elastic Agent" title="Powershell commands to add an Elastic Agent" /></p>
<p>Of note, because all of our TLS certificates are self-signed, we need to append the <strong>–insecure</strong> flag. This is unnecessary if you are using trusted certificates.</p>
<pre><code>**.\elastic-agent.exe install --url=https://[stack-ip]:8220 --enrollment-token=[token] --insecure**
</code></pre>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt81a881deb2744127/6a7d85e3c2e9147205013d2f/image23.jpg" alt="Enrolling the Elastic Agent into Fleet" title="Enrolling the Elastic Agent into Fleet" /></p>
<p>Back in Kibana, we can see confirmation that the Elastic Agent installed on the host and that data is being recorded into Elasticsearch.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1531870d33eff14d/6a7d85e6b43770f5fa4d400a/image2.jpg" alt="Verifying Elastic Agent enrollment" title="Verifying Elastic Agent enrollment" /></p>
<p>We can see that the Elastic Agent is reporting into Fleet and is healthy.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf5fbe8c65eaea495/6a7d85e9227b1cdef75958aa/image28.png" alt="Verify Elastic Agent health" title="Verify Elastic Agent health" /></p>
<p>If we go into the Discover tab, we can see various event types reporting into Elasticsearch. We can generate some test data by opening <strong>notepad.exe</strong> , <strong>calc.exe</strong> , and <strong>ping.exe -t www.elastic.co</strong> on the host. From Discover, we can make a simple query to validate that we’re seeing the data:</p>
<pre><code>**process.name.caseless : (notepad.exe or ping.exe or calc.exe)**
</code></pre>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc5eaf015abd56c7b/6a7d85ecb4377058f24d4010/image7.png" alt="Verifying data is being sent to Elasticsearch" title="Verifying data is being sent to Elasticsearch" /></p>
<p>Now that we’ve validated that we’re seeing data. Let's fire some malware!</p>
<h2 id="testfiresomemalware">Test fire some malware</h2>
<p>There are a lot of places you can download malware from, but for this test, we’ll simply use the industry standard <a href="https://www.eicar.org/download-anti-malware-testfile/">EICAR anti malware test file</a> to check the functionality.</p>
<p>The EICAR test is a file that is universally identified by security vendors and is used to test the operation of anti malware software and platforms. It contains a single string and is non-malicious.</p>
<p>From within the Windows host, we’ll use Powershell to download the EICAR file.</p>
<pre><code>**Invoke-WebRequest -Uri "https://secure.eicar.org/eicar.com.txt" -OutFile "eicar.txt"**
</code></pre>
<p>As expected, the event was immediately identified by the Elastic Agent’s security integration.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta832ce5daa158007/6a7d85ef5967e53cbb5da5d1/image29.jpg" alt="Elastic Security detected the EICAR test file" title="Elastic Security detected the EICAR test file" /></p>
<p>After a few minutes, the events are recorded into the Security Solution within Kibana. You can get there by clicking on the hamburger menu and then clicking on the Alerts section.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt736475477ae8d2e8/6a7d85f177b034ec013fc6eb/image9.jpg" alt="Viewing Security alerts" title="Viewing Security alerts" /></p>
<p>Here we can see the alert populated.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd67c270ba3ee6490/6a7d85f463e959aacc73af2d/image11.png" alt="Alert in the Security Solution" title="Alert in the Security Solution" /></p>
<p>If we click on the Analyzer button, we can dig into the event to identify the process that generated the event.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5f5e15eacde6fd76/6a7d85f742a117096d9591ce/image12.jpg" alt="Analyzer button" title="Analyzer button" /></p>
<p>In our example, we can see <strong>powershell.exe</strong> generated the event and this includes the correlated network events - <strong>secure.eicar.org</strong> , which is where the EICAR test file was downloaded from.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6b3cc8941cd02955/6a7d85f977b03490253fc6ef/image13.jpg" alt="Analyzer view" title="Analyzer view" /></p>
<h2 id="summary">Summary</h2>
<p>In this publication, we introduced you to the Elastic Stack and an open source project that can be used to quickly and securely stand up the entire stack for testing, labs, and security research.</p>
<p>Kibana and the Security Solution are powerful tools that are built by incident responders, threat hunters, and intelligence analysts with security practitioners in mind. To learn more about how to use these tools, <a href="https://www.elastic.co/training/">Elastic has some great (free and paid) training</a> that can help learn how to use Kibana for threat hunting.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/the-elastic-container-project</link>
    <guid isPermaLink="false">the-elastic-container-project</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Andrew Pease,Colson Wilhoit,Derek Ditch]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta024165c0f4aaf69/6a7d85fce3a219c56b99c79e/blog-thumb-container-barge.jpg" length="0" type="image/jpeg"/>
    <pubDate>Wed, 01 Mar 2023 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Ingesting threat data with the Threat Intel Filebeat module]]></title>
    <description><![CDATA[Tutorial that walks through setting up Filebeat to push threat intelligence feeds into your Elastic Stack.]]></description>
    <content:encoded><![CDATA[<p>The ability for security teams to integrate threat data into their operations substantially helps their organization identify potentially malicious endpoint and network events using indicators identified by other threat research teams. In this blog, we’ll cover how to ingest threat data with the Threat Intel Filebeat module. In future blog posts, we’ll cover enriching threat data with the Threat ECS fieldset and operationalizing threat data with Elastic Security.</p>
<h2 id="elasticfilebeatmodules">Elastic Filebeat modules</h2>
<p>Elastic Filebeat modules simplify the collection, parsing, and visualization of data stored in common log formats. Elastic publishes a variety of <a href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-modules.html">Filebeat modules</a> that are focused on collecting the data you want for use within Elasticsearch. These modules provide a standardized and “turnkey” method to ingest specific data sources into the Elastic Stack.</p>
<p>Using these capabilities, the Threat Intel Filebeat module:</p>
<ul>
<li>Consumes threat data from six open source feeds</li>
<li>Loads threat data into Elasticsearch</li>
<li>Normalizes threat data into the <a href="https://www.elastic.co/guide/en/ecs/current/ecs-threat.html">Threat ECS fieldset</a></li>
<li>Enables threat analysis through dashboards and visualizations</li>
</ul>
<p>Analysts and threat hunters can use this data for raw threat hunting, enrichment, intelligence analysis and production, and detection logic.</p>
<p>![](/assets/images/ingesting-threat-data-with-the-threat-intel-filebeat-module/overview.jpg</p>
<p>The six feeds included with the 7.13 Filebeat Threat Intel module are as follows (additional feeds may be added in the future):</p>
<ul>
<li><a href="https://urlhaus-api.abuse.ch/v1/payloads/recent">Abuse.ch Malware</a></li>
<li><a href="https://urlhaus.abuse.ch/">Abuse.ch URL</a></li>
<li><a href="https://otx.alienvault.com/">AlienVault Open Threat Exchange (OTX)</a></li>
<li><a href="https://www.anomali.com/resources/limo">Anomali Limo</a></li>
<li><a href="https://bazaar.abuse.ch/">Malware Bazaar</a></li>
<li><a href="https://www.misp-project.org/">Malware Information Sharing Platform (MISP)</a></li>
</ul>
<p>Using the Threat Intel Filebeat module, you can choose from several open source threat feeds, store the data in Elasticsearch, and leverage the Kibana Security App to aid in security operations and intelligence analysis.</p>
<h2 id="threatintelfilebeatmodule">Threat Intel Filebeat module</h2>
<p>Generally, the Filebeat Threat Intel module can be started without any configuration to collect logs from Abuse.ch feeds, Anomali Limo, and Malware Bazaar. However, the optional AlienVault OTX and MISP datasets require tokens to authenticate to their feed sources. Thankfully, obtaining a token is a simple process.</p>
<h3 id="alienvaultotx">AlienVault OTX</h3>
<p>The team over at Alien Labs® has created the Open Threat Exchange (OTX)® as an open threat intelligence community. This environment provides access to a diverse community of researchers and practitioners. OTX allows anyone in the community to discuss, research, validate, and share threat data. Additionally, OTX has an Application Programming Interface (API) endpoint that provides a read-only feed; which is how the Filebeat module consumes the OTX threat data.</p>
<p>To access the OTX API, you simply need to <a href="https://otx.alienvault.com/">create an account</a>. Once you have an account, you can subscribe to specific OTX community reports and threat data feeds called “Pulses.” These Pulses are retrieved by the Filebeat module and stored in Elasticsearch.</p>
<p>Pulses are updated at various cadences, but many are daily or even hourly. The Pulse has a summary of the threat, indicators, and various other enrichments that can help you contextually assess the threat in your environment.</p>
<p>To subscribe to Pulses, select Browse → Pulses, and then subscribe to any Pulses that you’d like. You can sort by the most recently modified to identify the most active Pulses.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7cd758466c93c9ff/6a7d8c1473d9bd8ba929ad42/av-pulse.jpg" alt="" /></p>
<p>Now that you’ve subscribed to Pulses of interest, we’ll need to collect your API key.</p>
<h3 id="retrievingyourapikey">Retrieving Your API Key</h3>
<p>The API key is used to securely authenticate to OTX and obtain the indicators from Pulses.</p>
<p>To retrieve your API key, select your userID → Settings, and then copy your OTX Key.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc3cba6dcb28af426/6a7d8c186693f805ab6611ab/av-api.jpg" alt="" /></p>
<p>Now that we have your OTX Key, let’s set up MISP.</p>
<h2 id="misp">MISP</h2>
<p>The Malware Information Sharing Platform (MISP) is an open source project for collecting, storing, distributing, and sharing indicators about threats.</p>
<p>While MISP is extremely powerful and has a tremendous variety of features, it can be a bit cumbersome to set up. If you are planning on setting up MISP for production, check out the <a href="https://github.com/MISP/MISP/tree/2.4/docs">official documentation</a> for installing MISP on Kali, RHEL (incl. CentOS and Fedora), or Ubuntu.</p>
<p>If your organization doesn’t have a MISP instance, you can use one of the many projects that use Docker to get MISP up and running. There’s a <a href="https://github.com/coolacid/docker-misp">great and maintained project</a> by Jason Kendall (@coolacid) that is about as turnkey as you could ask for.</p>
<h3 id="standingupcoolacidsmispdockercontainers">Standing up CoolAcid’s MISP Docker Containers</h3>
<p>As a caveat, this will cover a default development deployment of MISP. It should not be used in production. Please see the <a href="https://github.com/MISP/MISP/tree/2.4/docs">official MISP documentation</a> for properly deploying a secure MISP instance.</p>
<p>As a few prerequisites, you’ll need to have Docker Compose and Git installed:</p>
<ul>
<li><strong>Docker Compose</strong> is used to automate the deployment and configuration of the containers. You can check out <a href="https://docs.docker.com/compose/install/">Docker’s documentation</a> on getting Compose installed.</li>
<li><strong>Git</strong> is a version-control framework used to coordinate software development throughout contributors and community members. You can check out the <a href="https://git-scm.com/book/en/v2/Getting-Started-Installing-Git">Git documentation</a> on getting Git installed.</li>
</ul>
<p>Next, we need to clone CoolAcid’s repository and fire up the containers.</p>
<ul>
<li>git clone: Copies the remote repository to your local machine into a file called “docker-misp”</li>
<li>cd docker-misp: Changes into the “docker-misp” directory</li>
<li>docker-compose up -d: Uses the docker-compose file in the “docker-misp” directory to download, build, and start all of the relevant containers in “detached mode” (in the background)</li>
</ul>
<pre><code>Code Block 1 - Starting MISP Containers

$ git clone https://github.com/coolacid/docker-misp.git
$ cd docker-misp
$ docker-compose up -d

Pulling misp (coolacid/misp-docker:core-latest)...
core-latest: Pulling from coolacid/misp-docker
a54cbf64e415: Pull complete
84e78d2508ee: Pull complete
433476aac54e: Pull complete
780a2dfa04f6: Pull complete
Digest: sha256:7f380ad0d858bdec2c4e220f612d80431b1a0b0cb591311ade38da53b50a4cc1
Status: Downloaded newer image for coolacid/misp-docker:core-latest
Pulling misp-modules (coolacid/misp-docker:modules-latest)...
modules-latest: Pulling from coolacid/misp-docker
cdd040608d7b: Pull complete
4e340668f524: Pull complete
a4501f203bb2: Downloading [=========================================&gt;         ]  166.1MB/201.3MB
2cdaa3afcfca: Download complete
99a18a4e84d6: Downloading [=============================&gt;                     ]  130.8MB/218.3MB
...
</code></pre>
<p>Once all of the containers are started, simply browse to <a href="https://localhost:8080">https://localhost</a> and log in with the default credentials of admin@admin.test and a passphrase of admin. You will immediately be required to change your passphrase.</p>
<h3 id="configuringdefaultmispfeeds">Configuring default MISP feeds</h3>
<p>Once you have started the MISP containers and changed your default credentials, hover over Sync Actions and then select List Feeds.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2419fd2e687bf5b5/6a7d8c1a6c6eac796af114a3/misp-listfeeds.jpg" alt="" /></p>
<p>Highlight the available feeds, select “Enable selected” to enable the default feeds, and then “Fetch and store all feed data.”</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt25c68b987fd9e584/6a7d8c1d96b5a65e51878772/misp-enablefeeds.jpg" alt="" /></p>
<p>Next, select on the “Event Actions” menu item, select “List Events” and you’ll see data begin to be populated. This will take a while.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt206dd77f0a250f18/6a7d8c2005b7b577f1188c71/misp-listevents.jpg" alt="" /></p>
<p>While the data provided by the MISP threat feeds is being downloaded, let’s get your API key.</p>
<h3 id="collectingyourapikey">Collecting Your API Key</h3>
<p>To collect your API key, select “Administration” and then “List Users.” You will see your account. Next to your “Authkey” will be an eye icon, select it to show your API key and copy that down.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb929a361f2298621/6a7d8c2333fa8a437f1ffa94/misp-api.jpg" alt="" /></p>
<p>Now that we have set up and configured MISP and retrieved our API key, we can configure the actual Filebeat module.</p>
<h2 id="installingfilebeat">Installing Filebeat</h2>
<p>Getting the Threat Intel module is no different than any other Filebeat module. Check out the <a href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-installation-configuration.html">Quick Start guide to install Filebeat</a> either as a standalone binary or a package for macOS, Windows, or Linux.</p>
<h2 id="configuringthethreatintelfilebeatmodule">Configuring the Threat Intel Filebeat module</h2>
<p>Once you have Filebeat, we’ll simply enable the module (ensure filebeat is in your $PATH).</p>
<pre><code>Code Block 2 - Enabling the Threat Intel Filebeat Module

filebeat modules enable threatintel
</code></pre>
<p>Next, let’s configure feeds. We’ll do this by modifying the module configuration files. Depending on your OS and installation method, the configuration files will be located in different locations:</p>
<p>Windows</p>
<ul>
<li>C:\Program Files\Filebeat\modules.d\threatintel.yml</li>
<li>If installed with <a href="https://community.chocolatey.org/packages/filebeat">Chocolatey</a></li>
<li>C:\ProgramData\chocolatey\lib\filebeat\tools\modules.d\threatintel.yml</li>
</ul>
<p>macOS</p>
<ul>
<li>filebeat/modules.d/threatintel.yml</li>
<li>If installed with <a href="https://formulae.brew.sh/formula/filebeat">Homebrew</a></li>
<li>/usr/local/etc/filebeat/modules.d/threatintel.yml</li>
</ul>
<p>Linux</p>
<ul>
<li>filebeat/modules.d/threatintel.yml</li>
<li>If Installed with <a href="https://www.elastic.co/guide/en/beats/filebeat/current/setup-repositories.html#_apt">APT</a> or <a href="https://www.elastic.co/guide/en/beats/filebeat/current/setup-repositories.html#_yum">YUM / dnf</a></li>
<li>/etc/filebeat/modules.d/threatintel.yml</li>
</ul>
<p>Using whichever text editor you’re most comfortable with, open threatintel.yml and we’ll add your OTX API key, your MISP API key, and validate Anomali’s credential pair.</p>
<h3 id="abuseurlfeedconfiguration">Abuse URL feed configuration</h3>
<p>By default, the Abuse URL feed is enabled and does not need modification. The feed includes domain, URI, and URL indicators with additional context for significant dates, tags, submitter, status, etc.</p>
<pre><code>Code Block 3 - Configuring the Abuse URL Feed

abuseurl:
  enabled: true

  # Input used for ingesting threat intel data.
  var.input: httpjson

  # The URL used for Threat Intel API calls.
  var.url: https://urlhaus-api.abuse.ch/v1/urls/recent/

  # The interval to poll the API for updates.
  var.interval: 10m
</code></pre>
<h4 id="abusemalwarefeedconfiguration">Abuse malware feed configuration</h4>
<p>By default, the Abuse malware feed is enabled and does not need modification. The feed includes file hashes and hosts with additional context for significant dates, tags, status, etc.</p>
<pre><code>Code Block 4 - Configuring the Abuse Malware Feed

abusemalware:
    enabled: true

    # Input used for ingesting threat intel data.
    var.input: httpjson

    # The URL used for Threat Intel API calls.
    var.url: https://urlhaus-api.abuse.ch/v1/payloads/recent/

    # The interval to poll the API for updates.
    var.interval: 10m
</code></pre>
<h3 id="mispfeedconfiguration">MISP feed configuration</h3>
<p>By default, the MISP feed is enabled but requires configuration. The feed includes various file and network data with additional context for significant dates, tags, status, submitter, etc.</p>
<p>The API endpoint that Filebeat will query needs to be configured. If you are running MISP on the same system as Filebeat, you can use var.url: https://localhost/event/restSearch. If you are running MISP elsewhere, you’ll need to enter that hostname or IP address in lieu of localhost.</p>
<p>The API token is the “Authkey” that you retrieved during the previous MISP setup steps. You’ll enter that as the value for var.api_token:</p>
<p>If you are using a self-signed SSL certificate for MISP, you’ll want to disable the SSL verification mode by uncommenting the var.ssl.verification_mode: none line.</p>
<pre><code>Code Block 5 - Configuring the MISP Feed

misp:
    enabled: true

    # Input used for ingesting threat intel data, defaults to JSON.
    var.input: httpjson

    # The URL of the MISP instance, should end with "/events/restSearch".
    var.url: https://localhost/events/restSearch

    # The authentication token used to contact the MISP API. Found when looking at user account in the MISP UI.
    var.api_token: MISP-Authkey

    # Configures the type of SSL verification done, if MISP is running on self signed certificates
    # then the certificate would either need to be trusted, or verification_mode set to none.
    var.ssl.verification_mode: none

    # Optional filters that can be applied to the API for filtering out results. This should support the majority of
    # fields in a MISP context. For examples please reference the filebeat module documentation.
    #var.filters:
    #  - threat_level: [4, 5]
    #  - to_ids: true

    # How far back to look once the beat starts up for the first time, the value has to be in hours. Each request
    # afterwards will filter on any event newer than the last event that was already ingested.
    var.first_interval: 300h

    # The interval to poll the API for updates.
    var.interval: 5m
</code></pre>
<h3 id="alienvaultotxfeedconfiguration">AlienVault OTX feed configuration</h3>
<p>By default, the AlienVault OTX feed is enabled but requires configuration. The feed includes various file and network data with additional context for significant dates, tags, etc.</p>
<p>The API token is the “OTX Key” that you retrieved during the AlienVault OTX setup steps. You’ll enter that as the value for var.api_token:</p>
<pre><code>Code Block 6 - Configuring the AlienVault OTX Feed

otx:
  enabled: true

  # Input used for ingesting threat intel data
  var.input: httpjson

  # The URL used for OTX Threat Intel API calls.
  var.url: https://otx.alienvault.com/api/v1/indicators/export

  # The authentication token used to contact the OTX API, can be found on the OTX UI.
  Var.api_token: OTX-Key

  # Optional filters that can be applied to retrieve only specific indicators.
  #var.types: "domain,IPv4,hostname,url,FileHash-SHA256"

  # The timeout of the HTTP client connecting to the OTX API
  #var.http_client_timeout: 120s

  # How many hours to look back for each request, should be close to the configured interval.
  # Deduplication of events is handled by the module.
  var.lookback_range: 1h

  # How far back to look once the beat starts up for the first time, the value has to be in hours.
  var.first_interval: 400h

  # The interval to poll the API for updates
  var.interval: 5m
</code></pre>
<h3 id="anomalifeedconfiguration">Anomali feed configuration</h3>
<p>By default, the Anomali feed is enabled but requires configuration. The feed includes various file and network data with additional context for significant dates, tags, etc.</p>
<p>The default username and passphrase for the Limo feed is guest:guest, but are commented out. If you do not have other credential pairs, you can simply uncomment var.username and var.password.</p>
<p>At the time of this writing, Anomali has 11 collections that they provide as part of their Limo feed. The var.url variable is where the collection is defined. To get a list of the collections, you can query the Anomali Limo collections API endpoint (while not required, <a href="https://stedolan.github.io/jq/download/">jq</a> makes the collections easier to read).</p>
<pre><code>Code Block 7 - Configuring the Anomali Limo Collections

$ curl -L -u guest:guest https://limo.anomali.com/api/v1/taxii2/feeds/collections | jq

{
  "collections": [
    {
      "can_read": true,
      "can_write": false,
      "description": "",
      "id": "107",
      "title": "Phish Tank"
    },
    {
      "can_read": true,
      "can_write": false,
      "description": "",
      "id": "135",
      "title": "Abuse.ch Ransomware IPs"
    },
    {
      "can_read": true,
      "can_write": false,
      "description": "",
      "id": "136",
      "title": "Abuse.ch Ransomware Domains"
    },
...
</code></pre>
<p>The collection ID can be inserted into the Anomali configuration. There are a few ways to do this. You can:</p>
<ul>
<li>Manually change the ID</li>
<li>Enter all of the IDs and comment out all but the collection you’re wanting to target</li>
<li>Create a duplicate Anomali configuration section for each collection</li>
</ul>
<p>The below example shows the approach of duplicate sections for each collection; notice the different collection ID for each section (31, 313, 33) in the var.url: field.</p>
<pre><code>Code Block 8 - Configuring the Anomali Limo Feed

  anomali:
    enabled: true

    # Input used for ingesting threat intel data
    var.input: httpjson

    # The URL used for Threat Intel API calls. Limo has multiple different possibilities for URL's depending
    # on the type of threat intel source that is needed.
    var.url: https://limo.anomali.com/api/v1/taxii2/feeds/collections/31/objects

    # The Username used by anomali Limo, defaults to guest.
    var.username: guest

    # The password used by anomali Limo, defaults to guest.
    var.password: guest

    # How far back to look once the beat starts up for the first time, the value has to be in hours.
    var.first_interval: 400h

    # The interval to poll the API for updates
    var.interval: 5m

  anomali:
    enabled: true

    # Input used for ingesting threat intel data
    var.input: httpjson

    # The URL used for Threat Intel API calls. Limo has multiple different possibilities for URL's depending
    # on the type of threat intel source that is needed.
    var.url: https://limo.anomali.com/api/v1/taxii2/feeds/collections/313/objects

    # The Username used by anomali Limo, defaults to guest.
    var.username: guest

    # The password used by anomali Limo, defaults to guest.
    var.password: guest

    # How far back to look once the beat starts up for the first time, the value has to be in hours.
    var.first_interval: 400h

    # The interval to poll the API for updates
    var.interval: 5m

  anomali:
    enabled: true

    # Input used for ingesting threat intel data
    var.input: httpjson

    # The URL used for Threat Intel API calls. Limo has multiple different possibilities for URL's depending
    # on the type of threat intel source that is needed.
    var.url: https://limo.anomali.com/api/v1/taxii2/feeds/collections/33/objects
...
</code></pre>
<p>Now that we’ve configured the module to consume threat feed data, let’s send the data into Elasticsearch and visualize it with Kibana.</p>
<h2 id="settingupelasticsearchandkibana">Setting up Elasticsearch and Kibana</h2>
<p>The Filebeat Threat Intel module will send the configured threat feed data into Elasticsearch, which can be visualized with Kibana. Please see the Elastic documentation for setting up <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/setup.html">Elasticsearch</a> and <a href="https://www.elastic.co/guide/en/kibana/current/setup.html">Kibana</a> production environments. Additionally, if you’re looking for a turnkey approach, you can quickly and securely set up an <a href="https://cloud.elastic.co">Elastic Cloud</a> account.</p>
<p>For this non-production example, we’ll be using one of the many projects that use Docker to get Elasticsearch and Kibana up and running quickly.</p>
<h3 id="standingupanelasticsearchandkibanacontainer">Standing up an Elasticsearch and Kibana container</h3>
<p>As a caveat, this will cover a convenient default development deployment of Elasticsearch and Kibana. It should not be used in production. Please see the <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/configuring-stack-security.html">Elastic documentation</a> for properly deploying a secure instance.</p>
<p>We’ll simply collect the repository and start the Docker containers.</p>
<ul>
<li>git clone: This copies the remote repository to your local machine into a folder called “elastic-container”</li>
<li>cd elastic-container: Changes into the “elastic-container” directory</li>
<li>sh elastic-container.sh start: This downloads and starts the Elasticsearch and Kibana containers</li>
</ul>
<pre><code>Code Block 9 - Starting Elastic Containers

$ git clone https://github.com/peasead/elastic-container.git
$ cd elastic-container
$ sh elastic-container.sh start

7.12.1: Pulling from elasticsearch/elasticsearch
ddf49b9115d7: Already exists
4df4d6995ad2: Pull complete
e180ce5d1430: Pull complete
b3801a448e4f: Downloading [====&gt;                      ]  199.3MB/353.1MB
a3100bfb487c: Download complete
817ce7c869c7: Download complete
485f138f2280: Download complete

7.12.1: Pulling from kibana/kibana
ddf49b9115d7: Already exists
588c50b1b6af: Extracting [====================&gt;       ]  34.93MB/40.52MB
9d32826b6fa0: Download complete
01017880c9d9: Download complete
efcedd43b7be: Download complete
0887ad2a14e0: Download complete
625b277c1f7b: Downloading [=====&gt;                     ]  52.27MB/320.4MB
68815bc8856d: Download complete
e9e0d8f8fa8c: Download complete
</code></pre>
<p>Check out the repository <a href="https://github.com/peasead/elastic-container">documentation</a> for additional usage and configuration options (if needed).</p>
<p>Once all of the containers are started, simply browse to <a href="https://localhost:5601">http://localhost:5601</a> and log in with the default credentials of elastic and a passphrase of password.</p>
<h2 id="consumingthreatdatawithfilebeat">Consuming threat data with Filebeat</h2>
<p>There are multiple <a href="https://www.elastic.co/guide/en/beats/filebeat/current/configuring-output.html">output options for Filebeat</a>, so use whatever is easiest for you. We’ll use a local Elasticsearch instance in this example. Using a local instance of Elasticsearch and Kibana requires no modification to the filebeat.yml file.</p>
<p>To validate our configuration, let’s first test our configuration and access to Elasticsearch.</p>
<ul>
<li>filebeat test config: This will test to ensure your filebeat.yml configuration is correct (if you modified it to fit your environment)</li>
<li>filebeat test output - this will test to ensure you can access Elasticsearch</li>
</ul>
<pre><code>Code Block 10 - Testing Filebeat Configuration and Connection

$ filebeat test config
Config OK

$ filebeat test output
elasticsearch: http://localhost:9200...
  parse url... OK
  connection...
    parse host... OK
    dns lookup... OK
    addresses: ::1, 127.0.0.1
    dial up... OK
  TLS... WARN secure connection disabled
  talk to server... OK
  version: 7.12.0
</code></pre>
<p>To load the dashboards, index pattern, and ingest pipelines, let’s run the setup.</p>
<ul>
<li>filebeat setup: This will connect to Kibana and load the index pattern, ingest pipelines, and the saved objects (tags, visualizations, and dashboards)</li>
</ul>
<pre><code>Code Block 11 - Setting Up Filebeat Index Patterns and saved objects in Kibana

$ filebeat setup

Overwriting ILM policy is disabled. Set `setup.ilm.overwrite: true` for enabling.

Index setup finished.
Loading dashboards (Kibana must be running and reachable)
Loaded dashboards
Setting up ML using setup --machine-learning is going to be removed in 8.0.0. Please use the ML app instead.
See more: https://www.elastic.co/guide/en/machine-learning/current/index.html
Loaded machine learning job configurations
Loaded Ingest pipelines
</code></pre>
<p>Finally, let’s <a href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-starting.html">start Filebeat</a> to begin collecting!</p>
<p>Next, browse to Kibana and select the Dashboards app. To make the dashboards easier to find, they all use the “threat intel” tag.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7919c0760deae8a1/6a7d825f73d9bddd1829ac27/filebeat-dashboards.jpg" alt="" /></p>
<p>There is a dashboard for each feed and an overview dashboard that shows the health of the module.</p>
<p>![](/assets/images/ingesting-threat-data-with-the-threat-intel-filebeat-module/overview.jpg</p>
<p>It may take several minutes for all of the data to be retrieved as the different sources are polled.</p>
<h2 id="whatsnext">What’s next?</h2>
<p>We’re working on converting the existing visualizations into <a href="https://www.elastic.co/kibana/kibana-lens">Lens</a> and adding <a href="https://www.elastic.co/guide/en/kibana/current/drilldowns.html">drilldown</a> capabilities to each visualization.</p>
<p>Additionally, as we mentioned in the beginning of this post, this is part one of a three-part series on operationalizing threat data in the Elastic Stack. The next post will cover enhancements to the Threat ECS fieldset and enriching threat data using local endpoint and network observations.</p>
<p>We’re working on adding additional open source and commercial feeds. If you have feeds that you’d like to see prioritized, please check out the contribution section below.</p>
<p>Finally, we’re looking at opportunities to add context and enrichments to observed events with third-party sources.</p>
<p>So stay tuned — we’re continuing to lean hard into empowering our customers to defend their environments. Being able to action threat data is a key part of that journey.</p>
<h2 id="howcanyoucontribute">How can you contribute?</h2>
<p>The <a href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-threatintel.html">Threat Intel Filebeat module</a> was released with Elastic 7.12, which means that it is still in beta. Testing the feeds, configurations, visualizations, etc. is strongly encouraged. We love hearing feedback.</p>
<p>In addition to the Threat Intel module, there are some other repositories that are related to the collection, processing, and analysis of TI data:</p>
<ul>
<li>The Beats <a href="https://github.com/elastic/beats">repository</a>, where you can contribute to, and enhance, threat data feeds</li>
<li>The Elastic Common Schema (ECS) <a href="https://github.com/elastic/ecs">repository</a>, where you can be a part of the discussion on shaping how threat data is described in the Elastic Stack</li>
<li>The Kibana <a href="https://github.com/elastic/kibana">repository</a>, where analysts interact with the data stored in Elasticsearch</li>
<li>The Detection Rules <a href="https://github.com/elastic/detection-rules">repository</a>, where detection logic and rules are created and stored</li>
</ul>
<p>The best way to contribute to the community is to explore the functionality, features, and <a href="https://www.elastic.co/guide/en/beats/filebeat/7.12/filebeat-module-threatintel.html">documentation</a> and let us know through a <a href="https://github.com/elastic/beats/issues/new/choose">Github Issue</a> if there is a problem or something you’d like to see.</p>
<p>If you’re new to Elastic, experience our latest version of the <a href="https://www.elastic.co/elasticsearch/service">Elasticsearch Service</a> on Elastic Cloud. Also be sure to take advantage of our <a href="https://www.elastic.co/training/elastic-security-quick-start">Quick Start training</a> to set yourself up for success.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/ingesting-threat-data-with-the-threat-intel-filebeat-module</link>
    <guid isPermaLink="false">ingesting-threat-data-with-the-threat-intel-filebeat-module</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Andrew Pease,Marius Iversen]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2ba1f854c69848ac/6a7d82621967ea7e5932d8c9/photo-edited-12-t.jpg" length="0" type="image/jpeg"/>
    <pubDate>Wed, 01 Mar 2023 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[NETWIRE Dynamic Configuration Extraction]]></title>
    <description><![CDATA[Elastic Security Labs discusses the NETWIRE trojan and is releasing a tool to dynamically extract configuration files.]]></description>
    <content:encoded><![CDATA[<h2 id="keytakeaways">Key takeaways</h2>
<ul>
<li>NETWIRE has shown an increase in prevalence over the last year</li>
<li>Elastic Security Labs created an extractor to pull out configuration data from NETWIRE files and memory dumps targeting the functions the malware uses to extract its encrypted data</li>
<li>The NETWIRE extractor is freely available for download</li>
</ul>
<blockquote>
  <p>To download the NETWIRE configuration extractor, check out our post on the tool:</p>
  <ul>
  <li><a href="https://www.elastic.co/security-labs/netwire-configuration-extractor">NETWIRE configuration extractor</a></li>
  </ul>
</blockquote>
<h2 id="preamble">Preamble</h2>
<p><a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.netwire">NETWIRE</a> is a Remote Access Tool (RAT) that has been used since at least 2014. It is a publicly available commodity malware and has been observed being used by financially motivated and nation-state actors.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte91ad1dc8dea9a6c/6a7d837e448e4edf0f5bdb7a/image1.jpg" alt="NETWIRE observations over the past 12-months" title="NETWIRE observations over the past 12-months" /></p>
<p>In the second half of 2022, we noticed an uptick in the prevalence of NETWIRE usage in our telemetry data. This prompted the Elastic Security Labs team to develop a configuration extractor to assist the security community in collecting atomic indicators within the configurations. Using this extractor will support threat tracking and improve detection, prevention, and response times.</p>
<h2 id="extractor">Extractor</h2>
<p>The NETWIRE RAT uses the <a href="https://en.wikipedia.org/wiki/RC4">RC4 symmetric encryption</a> algorithm to protect its configuration which is encrypted in the <strong>.data</strong> section along with the 16 bytes long RC4 decryption key.</p>
<p>While reversing our samples the analysts noticed that for both the <strong>crypto::rc4_init_sbox</strong> and <strong>crypto::rc4_decrypt</strong> functions the second argument (#2 in the image below) is always a memory address for the desired encrypted configuration value, and the third argument (#3) is an immediate value written to the memory stack before the call which represents the size of the encrypted string.</p>
<p>It was also noted that the function calls are one after the other. This is important to allow us to structure the extractor to look for these functions sequentially.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt216d47cc066691a1/6a7d838105b7b5285a188b8a/image4.png" alt="NETWIRE's assembly code for the decryption function" title="NETWIRE's assembly code for the decryption function" /></p>
<p>With <strong>$key</strong> (from the above image) in mind, we created YARA rules to identify the location of the key and encrypted configuration values.</p>
<p>![YARA rule section that identifies the key and encrypted configuration](/assets/images/netwire-dynamic-configuration-extraction/image5.jpg</p>
<p>With this information we can then use <a href="http://www.capstone-engine.org/">Capstone</a> to:</p>
<ol>
<li><p>Locate the function responsible for decrypting the configuration using YARA.</p></li>
<li><p>Disassemble the function using Capstone.</p></li>
<li><p>Extract the RC4 key address and the encrypted configuration field addresses.</p></li>
<li><p>Extract the size of the configuration field.</p></li>
<li><p>RC4 decrypt the encrypted fields and rebuild the configuration.</p></li>
</ol>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0d2106af0fdc85fa/6a7d83848fc2d0d42e3eb8df/image2.jpg" alt="Locating the RC4 key address and the encrypted configuration" title="Locating the RC4 key address and the encrypted configuration" /></p>
<p>![RC4 decrypting the configuration](/assets/images/netwire-dynamic-configuration-extraction/image5.jpg</p>
<p>Once we have recreated the configuration, we can use the extractor to pull out several parameters used by NETWIRE, as well as a few basic file characteristics:</p>
<ul>
<li><strong>Active Setup Key</strong> : <a href="https://attack.mitre.org/techniques/T1547/014/">Active Setup</a> registry key to achieve persistence.</li>
<li><strong>C2 IP list</strong> : List of command and control (C2) server domains or IP addresses.</li>
<li><strong>Host ID</strong> : A unique identifier that is assigned to the infected machine.</li>
<li><strong>Installation path</strong> : The location where the malware will be installed.</li>
<li><strong>Keylogger logs directory</strong> : The location where the keylogging log file will be stored.</li>
<li><strong>Mutex</strong> : Mutex name, to create a synchronization object to ensure only one instance of the sample is running on the machine.</li>
<li><strong>Password</strong> : Static password to generate AES key used for encrypting the communication between the malware and the C2 server.</li>
<li><strong>Run registry key entry</strong> : Name of the entry in the <a href="https://attack.mitre.org/techniques/T1547/001/">run registry</a>, used for persistence.</li>
<li><strong>Sleep in seconds</strong> : The amount of time the malware sleeps.</li>
</ul>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf6f24aca3391a43a/6a7d83866c6eac927df11399/image6.jpg" alt="Sample output from configuration extractor" title="Sample output from configuration extractor" /></p>
<p>The configuration extractor accepts four parameters:</p>
<ul>
<li><strong>-f</strong> : to specify a single NETWIRE sample</li>
<li><strong>-d</strong> : To specify a directory of NETWIRE samples</li>
<li><strong>-o</strong> : To write the configuration in JSON format to the specified file</li>
<li><strong>--all-config</strong> : To print the unparsed raw decrypted configuration</li>
</ul>
<h2 id="analysis">Analysis</h2>
<p>We’ve used this extractor to examine a set of samples from the previous 180 days to extract indicators for further enrichment and analysis.</p>
<p>Our initially collected batch of samples came as a mixture of executable files and memory dumps. The extractor will only work on unmapped files, so the dumps which were already mapped were run through <a href="https://github.com/hasherezade/pe_unmapper"><strong>pe_unmapper</strong></a>.</p>
<p>When extracting a payload from memory, we are obtaining a memory-mapped version of it. This means that the <strong>"Raw Address"</strong> and <strong>"Raw Size"</strong> may not be correctly aligned with the correct section’s data. To correctly align the PE file, it is necessary to adjust the pointer to the raw address so that it matches the virtual address for every section.</p>
<p>Now we can run the configuration extractor with <a href="https://python-poetry.org/">Poetry</a> against our directory of unmapped binaries:</p>
<pre><code>**poetry lock**
**poetry install**
**poetry shell**
**netwire-config-extractor -d sample-dir/ -o output.ndjson**
</code></pre>
<p>This file, <strong>output.ndjson</strong> , can then be uploaded to Kibana for further analysis.</p>
<blockquote>
  <p>Check out the <a href="https://www.elastic.co/security-labs/the-elastic-container-project">Elastic Container project</a> to quick spin up an Elastic Stack and start analyzing structured security-relevant data.</p>
</blockquote>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt39ac8dfd2028f7b2/6a7d838a63e9593fe673aedb/image3.png" alt="Extracted NETWIRE configuration data" title="Extracted NETWIRE configuration data" /></p>
<p>Next time you run into a NETWIRE sample, run it through our configuration extractor to pull out other indicators to help you on your analytic journey or begin remediating quicker.</p>
<h2 id="detection">Detection</h2>
<h3 id="yara">YARA</h3>
<p>These YARA rules can used to detect and identify NETWIRE RAT.</p>
<pre><code>rule Windows_Trojan_Netwire_1 {
   meta:
       author = "Elastic Security"
       os = "Windows"
       arch = "x86"
       category_type = "Trojan"
       family = "Netwire"
       threat_name = "Windows.Trojan.Netwire"
   strings:
       $a = { 0F B6 74 0C 10 89 CF 29 C7 F7 C6 DF 00 00 00 74 09 41 89 F3 88 5C }
   condition:
       all of them
}
rule Windows_Trojan_Netwire_2 {
   meta:
       author = "Elastic Security"
       os = "Windows"
       arch = "x86"
       category_type = "Trojan"
       family = "Netwire"
       threat_name = "Windows.Trojan.Netwire"
   strings:
       $a1 = "[%.2d/%.2d/%d %.2d:%.2d:%.2d]" fullword
       $a2 = "\\Login Data"
       $a3 = "SOFTWARE\\NetWire" fullword
   condition:
       2 of them
}
rule Windows_Trojan_Netwire_3 {
   meta:
       author = "Elastic Security"
       os = "Windows"
       arch = "x86"
       category_type = "Trojan"
       family = "Netwire"
       threat_name = "Windows.Trojan.Netwire"
   strings:
       $a = { C9 0F 44 C8 D0 EB 8A 44 24 12 0F B7 C9 75 D1 32 C0 B3 01 8B CE 88 44 }
   condition:
       all of them
}
rule Windows_Trojan_Netwire_4 {
   meta:
       author = "Elastic Security"
       os = "Windows"
       arch = "x86"
       category_type = "Trojan"
       family = "Netwire"
       threat_name = "Windows.Trojan.Netwire"
   strings:
       $a1 = "http://%s%ComSpec" ascii fullword
       $a2 = "%c%.8x%s" ascii fullword
       $a3 = "%6\\6Z65dlNh\\YlS.dfd" ascii fullword
       $a4 = "GET %s HTTP/1.1" ascii fullword
       $a5 = "R-W65: %6:%S" ascii fullword
       $a6 = "PTLLjPq %6:%S -qq9/G.y" ascii fullword
   condition:
       4 of them
}
</code></pre>
<h2 id="indicators">Indicators</h2>
<p>All indicators are also available <a href="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte3d9f2700cdf6637/63d3f854e4e29e75dc5de351/9965-indicators.zip">for download</a> in both ECS and STIX format in a combined zip bundle.</p>
<p>The following indicators were discussed in this research.</p>
<p>| Indicator                              | Type        | Note           |
| -------------------------------------- | ----------- | -------------- |
| 139.28.38[.]235                        | ipv4-addr   | NETWIRE RAT C2 |
| 149.102.132[.]253                      | ipv4-addr   | NETWIRE RAT C2 |
| 184.75.221[.]115                       | ipv4-addr   | NETWIRE RAT C2 |
| 185.136.165[.]182                      | ipv4-addr   | NETWIRE RAT C2 |
| 185.140.53[.]139                       | ipv4-addr   | NETWIRE RAT C2 |
| 185.140.53[.]144                       | ipv4-addr   | NETWIRE RAT C2 |
| 185.140.53[.]154                       | ipv4-addr   | NETWIRE RAT C2 |
| 185.140.53[.]61                        | ipv4-addr   | NETWIRE RAT C2 |
| 185.216.71[.]251                       | ipv4-addr   | NETWIRE RAT C2 |
| 194.36.111[.]59                        | ipv4-addr   | NETWIRE RAT C2 |
| 194.5.98[.]126                         | ipv4-addr   | NETWIRE RAT C2 |
| 194.5.98[.]178                         | ipv4-addr   | NETWIRE RAT C2 |
| 194.5.98[.]188                         | ipv4-addr   | NETWIRE RAT C2 |
| 194.5.98[.]65                          | ipv4-addr   | NETWIRE RAT C2 |
| 212.193.29[.]37                        | ipv4-addr   | NETWIRE RAT C2 |
| 212.193.30[.]230                       | ipv4-addr   | NETWIRE RAT C2 |
| 213.152.161[.]249                      | ipv4-addr   | NETWIRE RAT C2 |
| 217.151.98[.]163                       | ipv4-addr   | NETWIRE RAT C2 |
| 23.105.131[.]166                       | ipv4-addr   | NETWIRE RAT C2 |
| 37.0.14[.]199                          | ipv4-addr   | NETWIRE RAT C2 |
| 37.0.14[.]203                          | ipv4-addr   | NETWIRE RAT C2 |
| 37.0.14[.]206                          | ipv4-addr   | NETWIRE RAT C2 |
| 37.0.14[.]208                          | ipv4-addr   | NETWIRE RAT C2 |
| 37.0.14[.]214                          | ipv4-addr   | NETWIRE RAT C2 |
| 37.120.217[.]243                       | ipv4-addr   | NETWIRE RAT C2 |
| 51.161.104[.]138                       | ipv4-addr   | NETWIRE RAT C2 |
| 54.145.6[.]146                         | ipv4-addr   | NETWIRE RAT C2 |
| 80.66.64[.]136                         | ipv4-addr   | NETWIRE RAT C2 |
| 85.209.134[.]105                       | ipv4-addr   | NETWIRE RAT C2 |
| 85.31.46[.]78                          | ipv4-addr   | NETWIRE RAT C2 |
| 94.156.35[.]40                         | ipv4-addr   | NETWIRE RAT C2 |
| 20220627.duckdns[.]org                 | domain-name | NETWIRE RAT C2 |
| admin96.hopto[.]org                    | domain-name | NETWIRE RAT C2 |
| alice2019.myftp[.]biz                  | domain-name | NETWIRE RAT C2 |
| asorock1111.ddns[.]net                 | domain-name | NETWIRE RAT C2 |
| banqueislamik.ddrive[.]online          | domain-name | NETWIRE RAT C2 |
| betterday.duckdns[.]org                | domain-name | NETWIRE RAT C2 |
| bigman2021.duckdns[.]org               | domain-name | NETWIRE RAT C2 |
| blazeblaze.ddns[.]net                  | domain-name | NETWIRE RAT C2 |
| chongmei33.myddns[.]rocks              | domain-name | NETWIRE RAT C2 |
| clients.enigmasolutions[.]xyz          | domain-name | NETWIRE RAT C2 |
| gracedynu.gleeze[.]com                 | domain-name | NETWIRE RAT C2 |
| ingobea.hopto[.]org                    | domain-name | NETWIRE RAT C2 |
| iphanyi.edns[.]biz                     | domain-name | NETWIRE RAT C2 |
| iphy.strangled[.]net                   | domain-name | NETWIRE RAT C2 |
| kimlee11.duckdns[.]org                 | domain-name | NETWIRE RAT C2 |
| loffgghh.duckdns[.]org                 | domain-name | NETWIRE RAT C2 |
| megaton.gleeze[.]com                   | domain-name | NETWIRE RAT C2 |
| moran101.duckdns[.]org                 | domain-name | NETWIRE RAT C2 |
| netuwaya.servecounterstrike[.]com      | domain-name | NETWIRE RAT C2 |
| nowancenorly.ddns[.]net                | domain-name | NETWIRE RAT C2 |
| podzeye.duckdns[.]org                  | domain-name | NETWIRE RAT C2 |
| podzeye2.duckdns[.]org                 | domain-name | NETWIRE RAT C2 |
| recoveryonpoint.duckdns[.]org          | domain-name | NETWIRE RAT C2 |
| redlinea[.]top                         | domain-name | NETWIRE RAT C2 |
| roller.duckdns[.]org                   | domain-name | NETWIRE RAT C2 |
| rozayleekimishere.duckdns[.]org        | domain-name | NETWIRE RAT C2 |
| sani990.duckdns[.]org                  | domain-name | NETWIRE RAT C2 |
| saturdaylivecheckthisout.duckdns[.]org | domain-name | NETWIRE RAT C2 |
| uhie.hopto[.]org                       | domain-name | NETWIRE RAT C2 |
| uhie2020.duckdns[.]org                 | domain-name | NETWIRE RAT C2 |
| wcbradley.duckdns[.]org                | domain-name | NETWIRE RAT C2 |
| xman2.duckdns[.]org                    | domain-name | NETWIRE RAT C2 |
| zonedx.ddns[.]net                      | domain-name | NETWIRE RAT C2 |</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/netwire-dynamic-configuration-extraction</link>
    <guid isPermaLink="false">netwire-dynamic-configuration-extraction</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Seth Goodwin,Salim Bitam]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4e2065614468fee2/6a7d838cbd2198acac755300/lock-code-combination-configuration.jpg" length="0" type="image/jpeg"/>
    <pubDate>Mon, 30 Jan 2023 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[NETWIRE Configuration Extractor]]></title>
    <description><![CDATA[Python script to extract the configuration from NETWIRE samples.]]></description>
    <content:encoded><![CDATA[<p>Python script to extract the payload from NETWIRE samples.</p>
<p><a href="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdcef1d05d2077d05/63d43627c31a7126813ff8b6/netwire-configuration-extractor.tar.gz">Download netwire-configuration-extractor.tar.gz</a></p>
<blockquote>
  <p>For information on the NETWIRE malware check out the following resources:</p>
  <ul>
  <li><a href="https://www.elastic.co/security-labs/netwire-dynamic-configuration-extraction">NETWIRE Dynamic Configuration Extraction</a></li>
  </ul>
</blockquote>
<h2 id="gettingstarted">Getting started</h2>
<h3 id="docker">Docker</h3>
<p>The recommended and easiest way to get going is to use Docker. From the directory this README is in, you can build a local container.</p>
<pre><code>docker build . -t netwire_loader_config_extractor
</code></pre>
<p>Then we run the container with the <strong>-v</strong> flag to map a host directory to the docker container directory.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data netwire_loader_config_extractor:latest --help
</code></pre>
<h3 id="runningitlocally">Running it locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
netwire-config-extractor --help
</code></pre>
<h2 id="usage">Usage</h2>
<p>All samples need to be unpacked prior to execution extraction attempts.</p>
<p>Our extractor takes either a directory of samples with <strong>-d</strong> option or <strong>-f</strong> for a single sample and then can output parts of the configuration of note, specifically:</p>
<ul>
<li><strong>-k</strong> : extract the encryption keys</li>
<li><strong>-c</strong> : extract the C2 information</li>
<li><strong>-s</strong> : extract the wide-character strings</li>
<li><strong>-a</strong> : extract the ASCII character strings</li>
</ul>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data netwire_loader_config_extractor:latest -d "C:\tmp\samples"
</code></pre>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd488d621e2daea68/6a7d837777b034175e3fc687/image6.jpg" alt="NETWIRE configuration extractor" title="NETWIRE configuration extractor" /></p>
<p>You can collect the extracted configurations from the directory you set when running the extractor.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/netwire-configuration-extractor</link>
    <guid isPermaLink="false">netwire-configuration-extractor</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Elastic Security Labs]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt57852b765fd03ec6/6a7d837a3ce8e28075cf26aa/tools-image.jpg" length="0" type="image/jpeg"/>
    <pubDate>Fri, 27 Jan 2023 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[QBOT Configuration Extractor]]></title>
    <description><![CDATA[Python script to extract the configuration from QBOT samples.]]></description>
    <content:encoded><![CDATA[<p>Python script to extract the configuration from QBOT samples.</p>
<p><a href="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta4523f3b586ba6ac/62e16e26d2f5267009ac073a/qbot-config-extractor.tar.gz">Download qbot-config-extractor.tar.gz</a></p>
<h2 id="gettingstarted">Getting Started</h2>
<p>This tool provides a Python module and command line tool that will extract configurations from the QBOT malware samples and dump the results to screen.</p>
<blockquote>
  <p>For information on the QBOT attack pattern and malware analysis, check out our blog posts detailing this:</p>
  <ul>
  <li><a href="https://www.elastic.co/security-labs/exploring-the-qbot-attack-pattern">Exploring the QBOT Attack Pattern</a></li>
  <li><a href="https://www.elastic.co/security-labs/qbot-malware-analysis">QBOT Malware Analysis</a></li>
  </ul>
</blockquote>
<h3 id="docker">Docker</h3>
<p>We can easily run the extractor with Docker, first we need to build the image:</p>
<pre><code>docker build . -t qbot-config-extractor
</code></pre>
<p>Then we run the container with the <strong>-v</strong> flag to map a host directory to the docker container directory:</p>
<pre><code>docker run -ti --rm -v \
"$(pwd)/data":/data qbot-config-extractor:latest -d /data/
</code></pre>
<p>We can either specify a single sample with <strong>-f</strong> option or a directory of samples with <strong>-d</strong>.</p>
<pre><code>$ docker run -ti --rm -v $(pwd)/data:/data qbot-config-extractor:latest -f data/c2ba065654f13612ae63bca7f972ea91c6fe97291caeaaa3a28a180fb1912b3a

=== Strings ===
# Blob address: 0x100840a0
# Key address: 0x10084040
[0x0]: ProgramData
[0xc]: /t4
[0x10]: EBBA
[0x15]: netstat -nao
[0x22]: jHxastDcds)oMc=jvh7wdUhxcsdt2
[0x40]: schtasks.exe /Create /RU "NT AUTHORITY\SYSTEM" /SC ONSTART /TN %u /TR "%s" /NP /F

...truncated...

=== RESOURCE 1 ===
Key: b'\\System32\\WindowsPowerShel1\\v1.0\\powershel1.exe'
Type: DataType.DOMAINS
41.228.22.180:443
47.23.89.62:995
176.67.56.94:443
103.107.113.120:443
148.64.96.100:443
47.180.172.159:443
181.118.183.98:443

...truncated...
</code></pre>
<h3 id="runningitlocally">Running it Locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
qbot-config-extractor -h
</code></pre>
<p>Once that works, you can do the same sort of things as mentioned in the Docker instructions above.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/qbot-configuration-extractor</link>
    <guid isPermaLink="false">qbot-configuration-extractor</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Elastic Security Labs]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6f02f18d4cdef033/6a7d83fea529e10c7b59c962/tools-image.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[ICEDID Configuration Extractor]]></title>
    <description><![CDATA[Python script to extract the configuration from ICEDID samples.]]></description>
    <content:encoded><![CDATA[<p>Python script to extract the payload from ICEDID samples.</p>
<p><a href="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt95ce19ae8cffda29/6351abcf20f42038fb989fae/icedid-config-extractor.tar.gz">Download icedid-configuration-extractor.tar.gz</a></p>
<blockquote>
  <p>For information on the ICEDID malware and network infrastructure, check out the following resources:</p>
  <ul>
  <li><a href="https://www.elastic.co/security-labs/icedids-network-infrastructure-is-alive-and-well">ICEDIDs network infrastructure is alive and well</a></li>
  <li><a href="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb86bffd1aef20c5b/6351aba34e565f1cdce29da5/icedid-checker.tar.gz">ICEDID network infrastructure checking utility</a></li>
  </ul>
</blockquote>
<h2 id="gettingstarted">Getting started</h2>
<h3 id="docker">Docker</h3>
<p>The recommended and easiest way to get going is to use Docker. From the directory this README is in, you can build a local container.</p>
<pre><code>docker build . -t icedid_loader_config_extractor
</code></pre>
<p>Then we run the container with the -v flag to map a host directory to the docker container directory.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data icedid_loader_config_extractor:latest --help
</code></pre>
<h3 id="runningitlocally">Running it locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
poetry lock
poetry install
poetry shell
icedid_loader_config_extractor --help
</code></pre>
<h2 id="usage">Usage</h2>
<p>All samples need to be unpacked prior to execution extraction attempts.</p>
<p>We can either specify a single sample with <strong>-f</strong> option or a directory of samples with <strong>-d</strong>.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data icedid_loader_config_extractor:latest -d "C:\tmp\samples"
</code></pre>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7792af5514f05d89/6a7d823551156a9a572bf899/196841115-5a3a0d95-8df4-45c2-9baa-264cfa9530e9.jpg" alt="ICEDID configuration extractor" title="ICEDID configuration extractor" /></p>
<p>You can collect the extracted configurations from the directory you set when running the extractor.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/icedid-configuration-extractor</link>
    <guid isPermaLink="false">icedid-configuration-extractor</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Elastic Security Labs]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4e5f28ba12e2f23b/6a7d8238bdcff04c02c40088/tools-image.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[BPFDoor Configuration Extractor]]></title>
    <description><![CDATA[Configuration extractor to dump out hardcoded passwords with BPFDoor.]]></description>
    <content:encoded><![CDATA[<p>Configuration extractor to dump out hardcoded passwords with BPFDoor.</p>
<p><a href="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3f57100ade3473c5/62882ccdb4fa6b61ed70ba87/bpfdoor-config-extractor.tar.gz">Download bpfdoor-config-extractor.tar.gz</a></p>
<h2 id="overview">Overview</h2>
<p>This tool provides a Python module and command line tool that will extract passwords from BPFDoor samples.</p>
<blockquote>
  <p>The Elastic Security Team has released an indepth analysis of the BPFDoor malware and created an additional tool that will scan for BPFDoor infected hosts.</p>
  <ul>
  <li><a href="https://bookish-bassoon-c37be003.pages.github.io/intelligence/2022/05/04.bpfdoor/article/">BPFDoor analysis</a></li>
  <li><a href="https://www.elastic.co/security-labs/bpfdoor-scanner">BPFDoor scanner</a></li>
  </ul>
</blockquote>
<h2 id="gettingstarted">Getting Started</h2>
<h3 id="docker">Docker</h3>
<p>We can easily run the extractor with Docker, first we need to build the image.</p>
<pre><code>Building the BPFDoor Docker image

docker build . -t bpfdoor-extractor
</code></pre>
<p>Then we run the container with the <strong>-v</strong> flag to map a host directory to the Docker container directory that contains the BPFDoor samples.</p>
<pre><code>Running the BPFDoor Docker container

docker run -ti --rm -v $(pwd)/binaries:/binaries \
  bpfdoor-extractor:latest -d /binaries/
</code></pre>
<p>We can either specify a single sample with <strong>-f</strong> option or a directory of samples with <strong>-d</strong></p>
<pre><code>BPFDoor Configuration Extractor help output

docker run -ti --rm bpfdoor-extractor:latest -h

Author: Elastic Security (MARE)

______ ______ ______ ______
| ___ \| ___ \|  ___||    \
| |_/ /| |_/ /| |_   | | | | ___    ___    __
| ___ \|  __/ |  _|  | | | |/  \  /  \ | '__|
| |_/ /| |    | |    | |/ /| (_) || (_) || |
\____/ \_|    \_|    |___/  \___/  \___/ |_|
 _____                 __            _____                             
/  __ \               / _|(_)        |  ___|     | |                    | |
| /  \/  ___    __  | |_     __   | |__ __  __| |_   __  __    ___ | |_  ___    __
| |     /  \ | '_ \ |  _|| | / _` | |  __|\ \/ /| __|| '__|/ _` | / __|| __|/  \ | '__|
| \__/\| (_) || | | || |  | || (_| | | |___ &gt;  &lt; | |_ | |  | (_| || (__ | |_| (_) || |
 \____/ \___/ |_| |_||_|  |_| \__, | \____//_/\_\ \__||_|   \__,_| \___| \__|\___/ |_|
                               __/ |
                              |___/


usage: bpfdoor-extractor [-h] (-f FILENAME | -d DIRNAME)

options:
  -h, --help            show this help message and exit
  -f FILENAME, --file FILENAME
                        File
  -d DIRNAME, --dir DIRNAME
                        Directory
</code></pre>
<h3 id="runningitlocally">Running it Locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
bpfdoor-extractor --help
</code></pre>
<p>Once that works, you can do the same sort of things as mentioned in the Docker instructions above.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/bpfdoor-configuration-extractor</link>
    <guid isPermaLink="false">bpfdoor-configuration-extractor</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Elastic Security Labs]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc7b6cb0fc160f109/6a7d7e01e02facaf7d5d34b4/tools-image.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[PARALLAX Payload Extractor]]></title>
    <description><![CDATA[Python script to extract the payload from PARALLAX samples.]]></description>
    <content:encoded><![CDATA[<p>Python script to extract the payload from PARALLAX samples.</p>
<p><a href="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdcec03c5c91923f5/633613d524bebb2394c2773d/parallax-payload-extractor.tar.gz">Download parallax-payload-extractor.tar.gz</a></p>
<blockquote>
  <p>For information on the PARALLAX malware loader and campaign observations, check out our <a href="https://elastic.co/security-labs/exploring-the-ref2731-intrusion-set">blog posts</a> detailing this intrusion set.</p>
</blockquote>
<h2 id="gettingstarted">Getting started</h2>
<h3 id="docker">Docker</h3>
<p>The recommended and easiest way to get going is to use Docker. From the directory this README is in, you can build a local container.</p>
<pre><code>docker build . -t parallax_loader_payload_extractor
</code></pre>
<p>Then we run the container with the -v flag to map a host directory to the docker container directory.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data parallax_loader_payload_extractor:latest --help
</code></pre>
<h3 id="runningitlocally">Running it locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
parallax_loader_payload_extractor --help
</code></pre>
<h2 id="usage">Usage</h2>
<p>We can either specify a single sample with <strong>-f</strong> option or a directory of samples with <strong>-d</strong>. You can use the -o switch to set the output directory of the payloads.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data parallax_loader_payload_extractor:latest -d /data -o /data
</code></pre>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd87e2e5bbf7eb516/6a7d8399ead8ecd027ba7b70/image41.jpg" alt="PARALLAX payload extractor" title="PARALLAX payload extractor" /></p>
<p>You can collect the extracted payloads from the directory you set when running the extractor, the data directory in the root of the extractor in the above example.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/parallax-payload-extractor</link>
    <guid isPermaLink="false">parallax-payload-extractor</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Elastic Security Labs]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt03c5c0ca9a9318b7/6a7d839c92013077ff352ca4/tools-image.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[BPFDoor Scanner]]></title>
    <description><![CDATA[Python script to identify hosts infected with the BPFDoor malware.]]></description>
    <content:encoded><![CDATA[<p>Python script to identify hosts infected with the BPFDoor malware.</p>
<p><a href="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltae9bafece9048014/62882b50dcc93261eccb04e2/bpfdoor-scanner.tar.gz">Download bpfdoor-scanner.tar.gz</a></p>
<h2 id="gettingstarted">Getting Started</h2>
<p>This tool provides a Python script to identify hosts that are infected with the BPFDoor malware.</p>
<blockquote>
  <p>The Elastic Security Team has released an indepth analysis of the BPFDoor malware and created an additional tool that will extract configurations from BPFDoor malware samples.</p>
  <ul>
  <li><a href="https://bookish-bassoon-c37be003.pages.github.io/intelligence/2022/05/04.bpfdoor/article/">BPFDoor analysis</a></li>
  <li><a href="https://www.elastic.co/security-labs/bpfdoor-configuration-extractor">BPFDoor configuration extractor</a></li>
  </ul>
</blockquote>
<h3 id="permissions">Permissions</h3>
<p>On Linux (and thus in a container), the tool requires the following permissions:</p>
<ul>
<li>CAP_NET_BIND_SERVICE</li>
<li>CAP_NET_RAW</li>
</ul>
<p>On any *NIX host, running the script with sudo will get you what you need. As long as you don’t strip the privileges listed for your container and you publish the UDP port you intend to receive on, you should be set.</p>
<h3 id="docker">Docker</h3>
<p>We can easily run the scanner with Docker, first we need to build the image:</p>
<pre><code>Building the BPFDoor scanner Docker image

docker build . -t bpfdoor-scanner
</code></pre>
<h2 id="usage">Usage</h2>
<p>Once you’be built the Docker iamge, we can run the container to get a list of the options.</p>
<pre><code>Runing the BPFDoor container

docker run -ti --rm bpfdoor-scanner:latest --help

Usage: bpfdoor-scanner [OPTIONS]

  Sends a discovery packet to suspected BPFDoor endpoints.

  Example usage:

      sudo ./bpfdoor-scanner --target-ip 1.2.3.4

  Sends a packet to IP 1.2.3.4 using the default target port 68/UDP (tool
  listens on all ports) using the default interface on this host and listens
  on port 53/UDP to masquerade as traffic.

  NOTE: Elevated privileges are required for source ports &lt; 1024.

Options:
  --target-ip TEXT       [required]
  --target-port INTEGER  [default: 68]
  --source-ip TEXT       IP for target to respond to and attempt to bind
                         locally  [default: 172.17.0.3]
  --source-port INTEGER  Local port to listen on for response  [default: 53]
  --timeout INTEGER      Number of seconds to wait for response  [default: 5]
  -v, --verbose          Show verbose output
  -d, --debug            Show debug output
  --version
  --help                 Show this message and exit.
</code></pre>
<p>The minimum required option is just --target-ip. The rest have defaults. For running in a container, you’ll want to publish the return port (defaults to 53) and specify --source-ip of the host interface you wish to use. In the following example, the IP 192.168.100.10 is the interface on my host that will receive the packet.</p>
<pre><code>Example running the BPFDoor scanner

docker run -ti --publish 53:53/udp --rm bpfdoor-scanner:latest \
  --target-ip 192.168.32.18 --source-ip 192.168.100.10
</code></pre>
<h2 id="runninglocally">Running Locally</h2>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>Running BPFDoor scanner locally

poetry lock
poetry install
poetry shell
sudo bpfdoor-scanner --help
</code></pre>
<p>Once that works, you can do the same sort of things as mentioned in the Docker instructions above.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/bpfdoor-scanner</link>
    <guid isPermaLink="false">bpfdoor-scanner</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Elastic Security Labs]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6ce4c91cdc9f01dd/6a7d7e051967ea8ccd32d829/tools-image.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Cobalt Strike Beacon Extractor]]></title>
    <description><![CDATA[Python script that collects Cobalt Strike memory data generated by security events from an Elasticsearch cluster, extracts the configuration from the CS beacon, and writes the data back to Elasticsearch.]]></description>
    <content:encoded><![CDATA[<p>Python script that collects Cobalt Strike memory data generated by security events from an Elasticsearch cluster, extracts the configuration from the CS beacon, and writes the data back to Elasticsearch.</p>
<p><a href="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdbc4f9f2366d2f06/628829603b9b8554904a4ba2/cobalt-strike-extractor.tar.gz">Download cobalt-strike-extractor.tar.gz</a></p>
<h2 id="overview">Overview</h2>
<p>This tool provides a Python module and command line tool that will search Elastic Endpoint alert data for detections of Cobalt Strike and the extracted memory data. When present, this tool will extract the implant configuration using the <a href="https://github.com/strozfriedberg/cobaltstrike-config-extractor">cobaltstrike-config-extractor</a>. The information is then normalized into an ECS-formatted JSON document and indexed into an Elasticsearch cluster or output to the terminal as JSON.</p>
<blockquote>
  <p>For help on creating Fleet policies to collect and analyze Cobalt Strike beacons in the Elastic Stack, check out our blog posts detailing this:</p>
  <ul>
  <li><a href="https://www.elastic.co/security-labs/collecting-cobalt-strike-beacons-with-the-elastic-stack">Collecting Colbalt Strike beacons</a></li>
  <li><a href="https://www.elastic.co/security-labs/extracting-cobalt-strike-beacon-configurations">Extracting Cobalt Strike beacon configurations</a></li>
  </ul>
</blockquote>
<h2 id="gettingstarted">Getting Started</h2>
<h3 id="docker">Docker</h3>
<p>The recommended and easiest way to get going is to use Docker. From the directory this README is in, you can build a local container.</p>
<pre><code>docker build . -t cobalt-strike-extractor
</code></pre>
<p>Next, make a copy of config.reference.yml and name it config.local.yml and edit for your environment. A minimal config looks like the example below. The input and output could use the same values, but you can optionally push it to a different cluster for analysis.</p>
<pre><code>## Using an Elastic Cloud instance (this is a randomly generated example)
input.elasticsearch:
  enabled: True
  cloud.id: security-cluster:dXMtd2VzdDEuZ2NwLmNsb3VkLmVzLmlvJGU0MWU1YTc3YmRjNzY2OTY0MDg2NjIzNDA5NzFjNjFkJDdlYjRlYTJkMzJkMTgzYTRiMmJkMjlkNTNjODhjMjQ4
  cloud.auth: elastic:&lt;PASSWORD&gt;

## Default output will use localhost:9092, see reference config
output.elasticsearch:
  enabled: True
  username: elastic
  password: &lt;PASSWORD&gt;
</code></pre>
<p>Now, run the container, passing in our local configuration. The -v flag here will add informational messages to the log output. Here, it tells us how many documents were successfully parsed and written.</p>
<pre><code>docker run -ti --rm -v "$(pwd)/config.local.yml:/config.yml" \
    cobalt-strike-extractor:latest -c /config.yml -v
</code></pre>
<p><em>Output</em>:</p>
<pre><code>[2022-01-10T21:33:31.493][INFO] Setting up input/output
[2022-01-10T21:33:31.493][INFO] Connecting to Elasticsearch for input
[2022-01-10T21:33:31.493][INFO] Successfully connected to Elasticsearch for input
[2022-01-10T21:33:31.834][INFO] Connecting to Elasticsearch for output
[2022-01-10T21:33:31.835][INFO] Successfully connected to Elasticsearch for output
[2022-01-10T21:33:33.030][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.078][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.093][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.096][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.097][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.097][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.097][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.098][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.186][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.191][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.461][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.516][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.927][INFO] Wrote 2 docs to Elasticsearch
</code></pre>
<p>The [WARNING] messages here are to be expected. These are simply source documents that didn’t contain the configuration information.</p>
<h4 id="filterbytime">Filter by time</h4>
<p>To limit the search by time frame, you can add the --since argument, which takes either an ISO-formatted date time string or you can use <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html#ranges-on-dates">Elastic date math</a>. For example, to limit search to the last 30 days, you can do the following.</p>
<pre><code>docker run -ti --rm -v "$(pwd)/config.local.yml:/config.yml" \
    cobalt-strike-extractor:latest --since "now-30d/d" -c config.local.yml
</code></pre>
<h4 id="pipeoutputtoothertools">Pipe output to other tools</h4>
<p>Lastly, you can pipe the output to other commands, such as jq to do local analysis. You can also override the configuration file values using environment variables.</p>
<pre><code>docker run -i --rm -a stdin -a stdout -a stderr \
    -v "$(pwd)/config.local.yml:/config.yml" \
    -e "OUTPUT_ELASTICSEARCH_ENABLED=False" \
    -e "OUTPUT_CONSOLE_ENABLED=True" cobalt-strike-extractor:latest -c /config.yml -q | jq  '.cobaltstrike.server.hostname'
</code></pre>
<p>In the example above, we disabled the Elasticsearch output and enabled the Console output using environment variables. We made the output more quiet using the -q flag (hiding the warnings). Then, we used jq to just pull out the “hostname” value of the configuration.</p>
<h3 id="runningitlocally">Running it Locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
cobalt-strike-extractor --help
</code></pre>
<p>Once that works, you can do the same sort of things as mentioned in the Docker instructions above.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/cobalt-strike-beacon-extractor</link>
    <guid isPermaLink="false">cobalt-strike-beacon-extractor</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Elastic Security Labs]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc57d646d784557c9/6a7d7e533ce8e2ca91cf25f4/tools-image.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[EMOTET Configuration Extractor]]></title>
    <description><![CDATA[Python script to extract the configuration from EMOTET samples.]]></description>
    <content:encoded><![CDATA[<p>Python script to extract the payload from EMOTET samples.</p>
<p><a href="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte2addf7080c31792/635ad4a5a739cc5f6cbd595e/emotet-configuration-extractor.tar.gz">Download emotet-configuration-extractor.tar.gz</a></p>
<blockquote>
  <p>For information on the EMOTET malware check out the following resources:</p>
  <ul>
  <li><a href="https://www.elastic.co/security-labs/emotet-dynamic-configuration-extraction">EMOTET Dynamic Configuration Extraction</a></li>
  </ul>
</blockquote>
<h2 id="gettingstarted">Getting started</h2>
<h3 id="docker">Docker</h3>
<p>The recommended and easiest way to get going is to use Docker. From the directory this README is in, you can build a local container.</p>
<pre><code>docker build . -t emotet-config-extractor
</code></pre>
<p>Then we run the container with the <strong>-v</strong> flag to map a host directory to the docker container directory.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data emotet-config-extractor:latest --help
</code></pre>
<h3 id="runningitlocally">Running it locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
emotet-config-extractor --help
</code></pre>
<h2 id="usage">Usage</h2>
<p>All samples need to be unpacked prior to execution extraction attempts.</p>
<p>Our extractor takes either a directory of samples with <strong>-d</strong> option or <strong>-f</strong> for a single sample and then can output parts of the configuration of note, specifically:</p>
<ul>
<li><strong>-k</strong> : extract the encryption keys</li>
<li><strong>-c</strong> : extract the C2 information</li>
<li><strong>-s</strong> : extract the wide-character strings</li>
<li><strong>-a</strong> : extract the ASCII character strings</li>
</ul>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data emotet-config-extractor:latest -d "C:\tmp\samples"
</code></pre>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4a8756e3178b5b8a/6a7d7fc32f00b29d28efbea6/image.jpg" alt="EMOTET configuration extractor" title="EMOTET configuration extractor" /></p>
<p>You can collect the extracted configurations from the directory you set when running the extractor.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/emotet-configuration-extractor</link>
    <guid isPermaLink="false">emotet-configuration-extractor</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Elastic Security Labs]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2d0a0aa0366c1ede/6a7d7fc6fc63ab2ba1649f74/tools-image.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[BLISTER Configuration Extractor]]></title>
    <description><![CDATA[Python script to extract the configuration and payload from BLISTER samples.]]></description>
    <content:encoded><![CDATA[<p>Python script to extract the configuration and payload from BLISTER samples.</p>
<p><a href="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9bce8a0e1a513bd5/62882db13b9b8554904a4baa/blister-config-extractor.tar.gz">Download blister-config-extractor.tar.gz</a></p>
<h2 id="gettingstarted">Getting Started</h2>
<p>This tool provides a Python module and command line tool that will extract configurations from the BLISTER malware loader and dump the results to screen.</p>
<blockquote>
  <p>For information on the BLISTER malware loader and campaign observations, check out our blog posts detailing this:</p>
  <ul>
  <li><a href="https://www.elastic.co/security-labs/elastic-security-uncovers-blister-malware-campaign">BLISTER Campaign Analysis</a></li>
  <li><a href="https://www.elastic.co/security-labs/blister-loader">BLISTER Malware Analysis</a></li>
  </ul>
</blockquote>
<h3 id="docker">Docker</h3>
<p>We can easily run the extractor with Docker, first we need to build the image:</p>
<pre><code>docker build . -t blister-config-extractor
</code></pre>
<p>Then we run the container with the <strong>-v</strong> flag to map a host directory to the docker container directory:</p>
<pre><code>docker run -ti --rm -v \
"$(pwd)/binaries":/binaries blister-config-extractor:latest -d /binaries/
</code></pre>
<p>We can either specify a single sample with <strong>-f</strong> option or a directory of samples with <strong>-d</strong>.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1d3d3ab4cfe665c6/6a7d7dfa73d9bdb2c929ab55/blister-configuration-extractor-image41.jpg" alt="BLISTER configuration extrator output" title="BLISTER configuration extrator output" /></p>
<h3 id="runningitlocally">Running it Locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
blister-config-extractor -h
</code></pre>
<p>Once that works, you can do the same sort of things as mentioned in the Docker instructions above.</p>
<h2 id="references">References</h2>
<ul>
<li>Customised Rabbit cipher implementation based on <a href="https://github.com/Robin-Pwner/Rabbit-Cipher/">Rabbit-Cipher</a></li>
</ul>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/blister-configuration-extractor</link>
    <guid isPermaLink="false">blister-configuration-extractor</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Elastic Security Labs]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1c3035bae58d1420/6a7d7dfd77b03461923fc5c8/tools-image.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[EMOTET Dynamic Configuration Extraction]]></title>
    <description><![CDATA[Elastic Security Labs discusses the EMOTET trojan and is releasing a tool to dynamically extract configuration files using code emulators.]]></description>
    <content:encoded><![CDATA[<h2 id="keytakeaways">Key takeaways</h2>
<ul>
<li>The EMOTET developers have changed the way they encode their configuration in the 64bit version of the malware.</li>
<li>Using code emulation we can bypass multiple code obfuscation techniques.</li>
<li>The use of code emulators in config extractors will become more prevalent in the future.</li>
</ul>
<blockquote>
  <p>To download the EMOTET configuration extractor, check out our post on the tool:</p>
  <ul>
  <li><a href="https://www.elastic.co/security-labs/emotet-configuration-extractor">EMOTET configuration extractor</a></li>
  </ul>
</blockquote>
<h2 id="preamble">Preamble</h2>
<p>The <a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.emotet">EMOTET</a> family broke onto the malware scene as a <a href="https://web.archive.org/web/20140701001622/https://blog.trendmicro.com/trendlabs-security-intelligence/new-banking-malware-uses-network-sniffing-for-data-theft/">modular banking trojan in 2014</a>, focused on harvesting and exfiltrating bank account information by inspecting traffic. EMOTET has been adapted as an early-stage implant used to load other malware families, such as <a href="https://www.elastic.co/security-labs/exploring-the-qbot-attack-pattern">QAKBOT</a>, <a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_Trickbot.yar">TRICKBOT</a>, and <a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Ransomware_Ryuk.yar">RYUK</a>. While multiple EMOTET campaigns have been dismantled by international law enforcement entities, it has continued to operate as one of the most prolific cybercrime operations.</p>
<p>For the last several months, Elastic Security has observed the EMOTET developers <a href="https://twitter.com/Cryptolaemus1/status/1516261512372965383?ref_src=twsrc%5Etfw">transition</a> to a 64-bit version of their malware. While this change does not seem to impact the core functionality of the samples we have witnessed, we did notice a change in how the configuration and strings are obfuscated. In earlier versions of EMOTET, the configuration was stored in an encrypted form in the <strong>.data</strong> section of the binary. In the newer versions the configuration is calculated at runtime. The information we need to extract the configuration from the binary is thus hidden within the actual code.</p>
<p>In the next sections, we’ll discuss the following as it relates to 64-bit EMOTET samples:</p>
<ul>
<li>EMOTET encryption mechanisms</li>
<li>Reviewing the EMOTET C2 list</li>
<li>Interesting EMOTET strings</li>
<li>The EMOTET configuration extractor utility</li>
</ul>
<h2 id="encryptionkeys">Encryption keys</h2>
<p>EMOTET uses embedded <a href="https://blog.cloudflare.com/a-relatively-easy-to-understand-primer-on-elliptic-curve-cryptography/">Elliptic Curve Cryptography</a> (ECC) public keys to encrypt their network communication. While in previous versions, the keys would be stored in an XOR-encrypted blob, now the content is calculated at runtime.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta88839fd08daa76f/6a7d7fcaea068d6679f071f6/image14.jpg" alt="Encoded Encryption Key blob in 64-bit version" title="Encoded Encryption Key blob in 64-bit version" /></p>
<p>In comparison the previous versions of EMOTET would store an encrypted version of the key data in the . <strong>text</strong> section of the binary.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt496ba98fcd3405cd/6a7d7fcdb43770a3e04d3f2d/image10.jpg" alt="Embedded key data in previous version of the malware" title="Embedded key data in previous version of the malware" /></p>
<p>In order to make it harder for security researchers to find the given code the malware uses <a href="https://www.usenix.org/conference/usenixsecurity21/presentation/liu-binbin">Mixed Boolean-Arithmetic</a> (MBA) as one of its obfuscation techniques. It transforms constants and simple expressions into expressions that contain a mix of Boolean and arithmetic operations.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9b08d8a036255158/6a7d7fcf437e0f2f7ddd8586/image6.jpg" alt="Example of Mixed Boolean-Arithmetic" title="Example of Mixed Boolean-Arithmetic" /></p>
<p>In this example, an array of constants is instantiated, but looking at the assembly we see that every constant is calculated at runtime. This method makes it challenging to develop a signature to target this function.</p>
<p>We noticed that both the <a href="https://cryptobook.nakov.com/asymmetric-key-ciphers/ecdh-key-exchange">Elliptic Curve Diffie-Hellman</a> (ECDH) and <a href="https://cryptobook.nakov.com/digital-signatures/ecdsa-sign-verify-messages">Elliptic Curve Digital Signature Algorithm</a> (ECDSA) keys use the same function to decode the contents.</p>
<p>The ECDH key (which you can recognize by its magic ECK1 bytes) is used for encryption purposes while the ECDSA key (ECC1) is used for verifying the C2 server's responses.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltceba22bf2f94fc56/6a7d7fd2e88c65760b00893a/image4.jpg" alt="ECK1 magic bytes at the start of the key data" title="ECK1 magic bytes at the start of the key data" /></p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7c29eea3e58b417a/6a7d7fd5b437701f764d3f33/image11.jpg" alt="Decoding algorithm for the key material" title="Decoding algorithm for the key material" /></p>
<p>By leveraging a YARA signature to find the location of this decode function within the EMOTET binary we can observe the following process:</p>
<ol>
<li>Find the decoding algorithm within the binary.</li>
<li>Locate any Cross References (<a href="https://hex-rays.com/blog/igor-tip-of-the-week-16-cross-references/">Xrefs</a>) to the decoding function.</li>
<li>Emulate the function that calls the decoding function.</li>
<li>Read the resulting data from memory.</li>
</ol>
<p>As we mentioned, we first find the function in the binary by using YARA. The signature is provided at the <a href="https://www.elastic.co/security-labs/emotet-dynamic-configuration-extraction#yara">end of this article</a>. It is worth pointing out that these yara signatures are used to identify locations in the binary but are, in their current form, not usable to identify EMOTET samples.</p>
<p>In order to automatically retrieve the data from multiple samples, we created a configuration extractor. In the snippets below, we will demonstrate, in a high level fashion, how we collect the configuration information from the malware samples.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6f6e020007aee7a8/6a7d7fd7bd21987fef75528f/image7.jpg" alt="Python code to find the start of a function" title="Python code to find the start of a function" /></p>
<p>In the above code snippet:</p>
<ol>
<li>First load the YARA signature.</li>
<li>Try to find a match, and if a signature is found in the file.</li>
<li>Calculate the function offset based on the offset in the file.</li>
</ol>
<p>In order to locate the Xrefs to this function, we use the excellent <a href="https://github.com/danielplohmann/smda">SMDA decompiler</a>. After locating the Xrefs, we can start the emulation process using the CPU emulator, <a href="https://www.unicorn-engine.org/">Unicorn</a>.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc1f316104a0699b7/6a7d7fda437e0f31bcdd858c/image8.jpg" alt="Python code used to emulate decoding functions" title="Python code used to emulate decoding functions" /></p>
<ol>
<li>Initialize the Unicorn emulator.</li>
<li>Load the executable code from the PE file into memory.</li>
<li>Disassemble the function to find the return and the end of the execution.</li>
<li>The binary will try to use the windows <a href="https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc">HeapAlloc API</a> to allocate space for the decoded data. Since we don't want to emulate any windows API's, as this would add unnecessary complexity, we hook to code so that we can allocate space ourselves.</li>
<li>After the emulation has run the 64-bit “long size” register (<a href="https://www.cs.uaf.edu/2017/fall/cs301/lecture/09_11_registers.html#:~:text=rax%20is%20the%2064%2Dbit,processors%20with%20the%2080386%20CPU.">RAX</a>), it will contain a pointer to the key data in memory.</li>
<li>To present the key in a more readable way, we convert it to the standard PEM format.</li>
</ol>
<p>By emulating the parts of the binary that we are interested in, we no longer have to statically defeat the obfuscation in order to retrieve the hidden contents. This approach adds a level of complexity to the creation of config extractors. However, since malware authors are adding ever more obfuscation, there is a need for a generic approach to defeating these techniques.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt29e8c12b880f9250/6a7d7fdde02fac707a5d34ee/image3.jpg" alt="Example of the extractor used to find key material" title="Example of the extractor used to find key material" /></p>
<h2 id="c2serverlist">C2 server list</h2>
<p>An important part of tracking malware families is to get new insights by identifying and discovering which C2 servers they use to operate their network.</p>
<p>In the 64-bit versions of EMOTET, we see that the IP and port information of the C2 servers are also dynamically calculated at runtime. Every C2 server is represented by a function that calculates and returns a value for the IP address and the port number.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt399a36b06bcde3b7/6a7d7fe01967ea132f32d877/image13.jpg" alt="Examples of encoded IP/port combination" title="Examples of encoded IP/port combination" /></p>
<p>These functions don’t have a direct cross reference available for searching. However, a procedure references all the C2 functions and creates the <strong>p_c2_list</strong> array of pointers.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd2b101678217fc1e/6a7d7fe363e959380173ae6c/image1.jpg" alt="C2 server list" title="C2 server list" /></p>
<p>After that, we can emulate every C2-server function individually to retrieve the IP and port combination as seen below.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8cba7db4edc3986a/6a7d7fe6227b1c5cba5957d8/image9.jpg" alt="Example of the extractor used to find C2 server list" title="Example of the extractor used to find C2 server list" /></p>
<h2 id="strings">Strings</h2>
<p>The same method is applied to the use of strings in memory. Every string has its own function. In the following example, the function would return a pointer to the string <strong>%s\regsvr32.exe "%s"</strong>.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0c89bcd54159e1f9/6a7d7fe896b5a62f9c8785fd/image15.jpg" alt="Encoded string" title="Encoded string" /></p>
<p>All of the EMOTET strings share a common function to decode or resolve the string at runtime. In the sample that we are analyzing here, the string resolver function is referenced 29 times.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2af2f1a172768e3e/6a7d7feb5588ade7ebee42c6/image2.jpg" alt="String decoding algorithm" title="String decoding algorithm" /></p>
<p>This allows us to follow the same approach as noted earlier in order to decode all of the EMOTET strings. We pinpoint the string decoding function using YARA, find the cross-references, and emulate the resulting functions.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb345276210a4812f/6a7d7fee63e959fac273ae7a/image12.jpg" alt="Example of the extractor used to find strings" title="Example of the extractor used to find strings" /></p>
<h2 id="configurationextractor">Configuration extractor</h2>
<p>Automating the payload extraction from EMOTET is a crucial aspect of threat hunting as it gives visibility of the campaign and the malware deployed by the threat actors, enabling practitioners to discover new unknown samples in a timely manner.</p>
<pre><code>% emotet-config-extractor --help
usage: Emotet Configuration Extractor [-h] (-f FILE | -d DIRECTORY) [-k] [-c] [-s] [-a]

options:
  -h, --help            show this help message and exit
  -f FILE, --file FILE  Emotet sample path
  -d DIRECTORY, --directory DIRECTORY
                        Emotet samples folder
  -k                    Extract Encryption keys
  -c                    Extract C2 information
  -s                    Extract strings
  -a                    Extract strings (ascii)
</code></pre>
<p>Our extractor takes either a directory of samples with <strong>-d</strong> option or <strong>-f</strong> for a single sample and then can output parts of the configuration of note, specifically:</p>
<ul>
<li><strong>-k</strong> : extract the encryption keys</li>
<li><strong>-c</strong> : extract the C2 information</li>
<li><strong>-s</strong> : extract the wide-character strings</li>
<li><strong>-a</strong> : extract the ASCII character stings</li>
</ul>
<p>EMOTET uses a different routine for decoding wide and ASCII strings. That is why the extractor provides flags to extract them separately.</p>
<p>The C2 information displays a list of IP addresses found in the sample. It is worth noting that EMOTET downloads submodules to perform specific tasks. These submodules can contain their own list of C2 servers. The extractor is also able to process these submodules.</p>
<p>The submodules that we observed do not contain encryption keys. While processing submodules you can omit the <strong>-k</strong> flag.</p>
<pre><code>[...]
[+] Key type: ECK1
[+] Key length: 32
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2DWT12OLUMXfzeFp+bE2AJubVDsW
NqJdRC6yODDYRzYuuNL0i2rI2Ex6RUQaBvqPOL7a+wCWnIQszh42gCRQlg==
-----END PUBLIC KEY-----
[...]
[+] Key type: ECS1
[+] Key length: 32
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9C8agzYaJ1GMJPLKqOyFrlJZUXVI
lAZwAnOq6JrEKHtWCQ+8CHuAIXqmKH6WRbnDw1wmdM/YvqKFH36nqC2VNA==
-----END PUBLIC KEY-----
[...]
[+] Found 64 c2 subs
174.138.33.49:7080
188.165.79.151:443
196.44.98.190:8080
[...]
[+] Starting emulation
[+] String BLOB address: 0x4000000
KeyDataBlob
[...]
[+] String BLOB address: 0x4000000
bcrypt.dll
[...]
[+] String BLOB address: 0x4000000
RNG
</code></pre>
<p>To enable the community to further defend themselves against existing and new variants of EMOTET, we are making the payload extractor open source under the Apache 2 License. Access the <a href="https://www.elastic.co/security-labs/emotet-configuration-extractor">payload extractor documentation and binary download</a>.</p>
<h2 id="thefutureofemotet">The future of EMOTET</h2>
<p>The EMOTET developers are implementing new techniques to hide their configurations from security researchers. These techniques will slow down initial analysis, however, EMOTET will eventually have to execute to achieve its purpose, and that means that we can collect information that we can use to uncover more about the campaign and infrastructure. Using code emulators, we can still find and extract the information from the binary without having to deal with any obfuscation techniques. EMOTET is a great example where multiple obfuscation techniques make static analysis harder. But of course, we expect more malware authors to follow the same example. That is why we expect to see more emulation-based configuration extract in the future.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt75d390264250ed82/6a7d7ff1ead8ec2853ba7b02/image5.png" alt="EMOTET running and gathering system information" title="EMOTET running and gathering system information" /></p>
<h2 id="detection">Detection</h2>
<h3 id="yara">YARA</h3>
<p>Elastic Security has created YARA rules to identify this activity. The YARA rules shown here are not meant to be used to solely detect EMOTET binaries, they are created to support the configuration extractor. The YARA rules for detecting EMOTET can be found in the <a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_Emotet.yar">protections-artifacts repository</a>.</p>
<h4 id="emotetkeydecryptionfunction">EMOTET key decryption function</h4>
<pre><code>rule resolve_keys
{
meta:
     author = "Elastic Security"
     description = "EMOTET - find the key decoding algorithm in the PE"
     creation_date = "2022-08-02"
     last_modified = "2022-08-11"
     os = "Windows"
     family = "EMOTET"
     threat_name = "Windows.Trojan.EMOTET"
     reference_sample = "debad0131060d5dd9c4642bd6aed186c4a57b46b0f4c69f1af16b1ff9c0a77b1"
   strings:
       $chunk_1 = {
        45 33 C9
        4C 8B D0
        48 85 C0
        74 ??
        48 8D ?? ??
        4C 8B ??
        48 8B ??
        48 2B ??
        48 83 ?? ??
        48 C1 ?? ??
        48 3B ??
        49 0F 47 ??
        48 85 ??
        74 ??
        48 2B D8
        42 8B 04 03
     }
   condition:
       any of them
}
</code></pre>
<h4 id="emotetc2aggregation">EMOTET C2 aggregation</h4>
<pre><code>rule c2_list
{
     author = "Elastic Security"
     description = "EMOTET - find the C2 collection in the PE"
     creation_date = "2022-08-02"
     last_modified = "2022-08-11"
     os = "Windows"
     family = "EMOTET"
     threat_name = "Windows.Trojan.EMOTET"
     reference_sample = "debad0131060d5dd9c4642bd6aed186c4a57b46b0f4c69f1af16b1ff9c0a77b1"
  strings:
     $chunk_1 = {
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
     }
  condition:
     any of them
}
</code></pre>
<h4 id="emotetstringdecoder">EMOTET string decoder</h4>
<pre><code>rule string_decode
{
   meta:
     author = "Elastic Security"
     description = "EMOTET - find the string decoding algorithm in the PE"
     creation_date = "2022-08-02"
     last_modified = "2022-08-11"
     os = "Windows"
     family = "EMOTET"
     threat_name = "Windows.Trojan.EMOTET"
     reference_sample = "debad0131060d5dd9c4642bd6aed186c4a57b46b0f4c69f1af16b1ff9c0a77b1"
  strings:
     $chunk_1 = {
        8B 0B
        49 FF C3
        48 8D 5B ??
        33 CD
        0F B6 C1
        66 41 89 00
        0F B7 C1
        C1 E9 10
        66 C1 E8 08
        4D 8D 40 ??
        66 41 89 40 ??
        0F B6 C1
        66 C1 E9 08
        66 41 89 40 ??
        66 41 89 48 ??
        4D 3B D9
        72 ??
     }
     $chunk_2 = {
        8B 0B
        49 FF C3
        48 8D 5B ??
        33 CD
        0F B6 C1
        66 41 89 00
        0F B7 C1
        C1 E9 ??
        66 C1 E8 ??
        4D 8D 40 ??
        66 41 89 40 ??
        0F B6 C1
        66 C1 E9 ??
        66 41 89 40 ??
        66 41 89 48 ??
        4D 3B D9
        72 ??
     }
  condition:
     any of them
}
</code></pre>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/emotet-dynamic-configuration-extraction</link>
    <guid isPermaLink="false">emotet-dynamic-configuration-extraction</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Remco Sprooten]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc2bf406679017439/6a7d7ff4c2cc090f3424664d/lock-code-combination-configuration.jpg" length="0" type="image/jpeg"/>
    <pubDate>Thu, 01 Dec 2022 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Handy Elastic Tools for the Enthusiastic Detection Engineer]]></title>
    <description><![CDATA[Tools like the EQLPlaygound, RTAs, and detection-rules CLI are great resources for getting started with EQL, threat hunting, and detection engineering respectively.]]></description>
    <content:encoded><![CDATA[<p>On August 3, we released Protections-artifacts as part of our Openness Initiative 🎉. One of the benefits of producing open and transparent security content is having the opportunity to work with a great community of security experts. In 2020, we discussed opening our detection rules — in continuing with that spirit, here is an inside peek of three available resources we use within Elastic’s Threat Research and Detection Engineering (TRaDE) team to aid our detection engineering research and development workflows.</p>
<p>TRaDE is responsible for the detection and endpoint behavior security rules that power Elastic’s XDR capabilities. While our detection rules provide visibility to adversary behaviors, the endpoint behavior rules have the capability to prevent an attack. These rules provide protection logic used by Elastic Endpoint Security to stop threats on Windows, Linux, and MacOS endpoints. Collectively, Elastic Security supports a wide range of platforms and data sources (e.g., core cloud service providers, K8s, core operating systems, etc.).</p>
<p>The two rulesets: a) detection rules and b) endpoint behavior rules, consider different use cases and complement each other to provide robust coverage. The comparison table highlights unique differences between the two in terms of protection design goals, how data is processed, and which data is processed.</p>
<p><a href="https://github.com/elastic/detection-rules/tree/main/rules">Detection Rules</a>- Design Goals: Provide the most robust detection coverage of all threats, leveraging all data sources available. Some tuning of rules based on organization-specific environments is expected. - Data Streams: Will search across all specified indexes per rule within a Stack. - Engine Processing: Batch process.</p>
<p><a href="https://github.com/elastic/protections-artifacts/tree/main/behavior">Endpoint Behavior</a>- Design Goals: Provide very high confidence, prevention-focused, minimal tuning at the expense of false negatives on a per-rule basis. We want every organization to be able to enable behavior protection and have a great experience out of the box, with little tuning required. - Data Streams: Agent searches data on the endpoint. - Engine Processing: Real time data streaming.</p>
<p>Behind the TRaDE crafting curtains, we leverage openly available tools to develop and test our rulesets. If you want a primer on writing Event Query Language (EQL) rules, want to generate suspicious activity to baseline your Elastic-powered detections, or quickly export those suspicious events from Elasticsearch, you may benefit from some of the tools we use. Section 1 introduces our security SIEM features via the EQLPlayground, section 2 discusses our rule testing capability RTA, and section 3 highlights our detection-rules CLI and a few valuable commands we use.</p>
<h2 id="eqlplayground">EQLPlayground</h2>
<p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/eql.html">EQL</a> was developed to express relationships between events, and, coupled with <a href="https://www.elastic.co/guide/en/ecs/current/index.html">ECS</a>, has the power to quickly correlate events across disparate data sources. Whether you want to perform a simple search with EQL, leverage advanced data stacking and filtering to discover anomalies, or define a complex hypothesis-based hunt query, EQL’s flexibility as a language can help improve your team’s effectiveness in many ways. The language is heavily <a href="https://cs.github.com/elastic/detection-rules?q=language+%3D+%22eql%22+path%3A%2F%5Erules%5C%2F%2F">used</a> (in addition to several other language options, enabling users to leverage the most relevant and applicable features) throughout our <a href="https://github.com/elastic/detection-rules">detection-rules repo</a> and <a href="https://github.com/elastic/protections-artifacts/tree/main/behavior">endpoint behavior artifacts</a> to detect adversary behaviors and express relationships between events.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt04be42ac30b04971/6a7d810c42a117690a95912b/image5.png" alt="EQL overview diagram" title="EQL overview diagram" /></p>
<p>While we strive to achieve feature parity between endpoint and elasticsearch EQL implementations to the extent possible, there are minor functional differences due to architectural implementations.</p>
<p>While reading about EQL can be very informative, playing with the query language is a much more fun and interactive learning experience! Thanks to Elastic’s own <a href="https://www.linkedin.com/in/jamesspiteri/">James Spiteri</a>, you can immediately dive into an Elastic Cloud Stack and learn using the <a href="https://eqlplayground.io/s/eqldemo/app/security/timelines/default?sourcerer=(default:(id:security-solution-eqldemo,selectedPatterns:!(eqldemo,%27logs-endpoint.*-eqldemo%27,%27logs-system.*-eqldemo%27,%27logs-windows.*-eqldemo%27,metricseqldemo)))&amp;timerange=(global:(linkTo:!(),timerange:(from:%272022-05-29T22:00:00.000Z%27,fromStr:now%2Fd,kind:relative,to:%272022-05-30T21:59:59.999Z%27,toStr:now%2Fd)),timeline:(linkTo:!(),timerange:(from:%272022-04-17T22:00:00.000Z%27,kind:absolute,to:%272022-04-18T21:59:59.999Z%27)))&amp;timeline=(activeTab:eql,graphEventId:%27%27,id:%279844bdd4-4dd6-5b22-ab40-3cd46fce8d6b%27,isOpen:!t)">EQLPlaygound</a>. The playground takes advantage of the native Security <a href="https://www.elastic.co/guide/en/security/current/timelines-ui.html">Timeline</a> correlation capabilities, and provides notes to enable learning EQL. The playground is a publicly available Elastic Security instance, pre-populated with suspicious events generated from a Sofacy group <a href="https://unit42.paloaltonetworks.com/unit42-sofacy-attacks-multiple-government-entities/">payload</a>. The only thing you need to access the site is a browser!</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc521649f9727ce7f/6a7d810f63e959965d73aeae/image3.png" alt="EQLPlayground" title="EQLPlayground" /></p>
<p>Essentially, you’re presented with a dataset representative of threat activity, similar to what we rely on to build our detection rules and endpoint artifacts. This event data can then be leveraged to generate your own detection logic. It also provides a small introduction to the Elastic Security Stack, and gives you an opportunity to play with some of the cool features available (e.g. Analyzer). The visual event <a href="https://www.elastic.co/guide/en/security/current/visual-event-analyzer.html">Analyzer</a> shows a graphical representation of a process tree, containing alerts and suspicious events detected by our Elastic Security Endpoint, and illustrates process lineage that can be used within a query.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt68d14982a9d72b07/6a7d81122f00b26338efbef5/image2.png" alt="Security app Analyzer interface" title="Security app Analyzer interface" /></p>
<p>We can use this information to understand how the adversary behavior works, and develop a query capable of identifying future malicious activity. For example, should Outlook spawn an explorer.exe child process? Explore the EQLPlayground, EQL <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/eql-syntax.html">syntax</a>, and <a href="https://www.elastic.co/guide/en/elasticsearch/reference/8.3/eql-apis.html">APIs</a>. In the correlation view <a href="https://www.elastic.co/blog/whats-new-elastic-security-7-12-0-analyst-driven-correlation-ransomware-prevention">introduced</a> with Elastic Security 7.12, you’ll have the opportunity to insert EQL and develop a query with your special sauce to detect the malicious behavior we’ve executed. You’ll also be able to look at each available field, and the data stream required to capture these events within your Stack.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltaa84a19f51f4ed92/6a7d811505b7b580b4188b5c/image4.png" alt="Security app Timeline correlation interface" title="Security app Timeline correlation interface" /></p>
<p>As you can see, there is an example placeholder query, but you have full access to modify the query based on the full event captured and come up with the best detection. Is there something suspicious about the process tree? What about the sequence of events? Is there something fishy about rundll32.exe (a commonly used <a href="https://attack.mitre.org/techniques/T1218/011/">execution proxy</a>) making external network calls?</p>
<pre><code>sequence by process.entity_id with maxspan=10s
[process where process.name : "rundll32.exe" and event.type == "start"]
[network where process.name : "rundll32.exe" and not cidrmatch(destination.ip, "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "127.0.0.0/8")]
</code></pre>
<p>We’d love to see what cool and clever queries you’ve come up with, and if you have ideas for new rules, check out our <a href="https://github.com/elastic/detection-rules/blob/main/CONTRIBUTING.md">CONTRIBUTING.md</a> guide and submit a <a href="https://github.com/elastic/detection-rules/issues/new?assignees=&amp;labels=Rule%3A+New&amp;template=new_rule.md&amp;title=%5BNew+Rule%5D+Name+of+rule">new rule</a>. For now, we’ll use this query in creating a rule with the detection-rule CLI.</p>
<h2 id="redteamautomationrta">Red Team Automation (RTA)</h2>
<p>One of the ways we automate testing Elastic’s ruleset is by launching RTA scripts that simulate threat behaviors. If you are unfamiliar with RTA, it is an open-source tool used by TRaDE to generate suspicious activity and unit test rules across multiple Stack releases. We encourage you to check out the <a href="https://www.elastic.co/blog/introducing-endgame-red-team-automation">2018 post</a> by <a href="https://www.linkedin.com/in/devonkerr/">Devon Kerr,</a> which introduced the capability.</p>
<p>Sometimes folks ask our team for sample data, methods to generate suspicious events to baseline configurations, or a testing environment with many alerts already generated in the Elastic Stack. We also regression test rules to validate new features added to the SIEM or Endpoint agent, any modifications based on rule tuning, or for maintenance. This process can become time-consuming with hundreds of rules to test across multiple Stack versions.</p>
<p>In the latest 8.4 dev cycle, we spent some time generating new macOS, Linux, and Windows RTAs. Consistent with the openness theme, we migrated our endpoint behavior tests to the Detection Rules <a href="https://github.com/elastic/detection-rules/tree/main/rta">repo</a> for the community! Current RTA development is focused on endpoint behavior, and we continue to expand the coverage of our rulesets with new RTAs, so look forward to even more RTAs in the not-too-distant future.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt702272ceb41a9fa2/6a7d8118dd26d219f52a726b/cloning_rta.jpg" alt="Cloning RTA" title="Cloning RTA" /></p>
<p>Once you’ve cloned the detection-rules repo, you’ll be able to list all available tests. Each RTA includes helpful metadata like the platform the RTA supports, the triggered rules that will alert, and the python code that generates suspicious activity on the target system. The <a href="https://github.com/elastic/detection-rules/blob/main/rta/common.py">common</a> import is packed with useful functions to simplify creating new RTAs. For example, it provides helper functionality to temporarily edit the Windows registry, check the required operating system is running the RTA, or even execute terminal commands. Essentially, it abstracts a lot of the common activity needed across the RTA set in order to simplify the development of new RTAs, especially for those less familiar with python. The RTA library was designed to use only stdlib Python packages so that no external dependencies would be required. Using only core libraries is greatly beneficial when testing in segmented environments.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf30cbde3a09a9fae/6a7d811a63e959568773aeb2/image_8.jpg" alt="Sample RTA edmond_child_process.py" title="Sample RTA edmond_child_process.py" /></p>
<p>In the above example, the RTA generates activity to trigger the <a href="https://github.com/elastic/detection-rules/blob/main/rules/macos/persistence_emond_rules_process_execution.toml">Suspicious Emond Child Process</a> SIEM and <a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/persistence_potential_persistence_via_emond.toml">Potential Persistence via Emond</a> endpoint behavior rules. The RTA creates a bash shell process spawned from a parent process called emond. We aim to make repeatable yet non-destructive test cases to reuse testing infrastructure as much as possible between unit tests. There are many approaches to generating suspicious events that would trigger these rules, so if you’d like to contribute your creative ideas, feel free to submit a pull request to the <a href="https://github.com/elastic/detection-rules">detection-rules</a>!</p>
<h2 id="detectionrulescli">Detection Rules CLI</h2>
<p>The detection-rules CLI is a development tool swiss-army-knife that we use to manage and test whether our rules pass validation, but there are useful commands that you can use to speed up rule testing in your own environment. If you’re familiar with Python3, getting started with the Detection Rules CLI commands will only take a few steps. It has useful commands like <code>view-rule</code> , which shows the rule as a JSON object in the format expected by Kibana. Conveniently, the command also validates while loading; if you ever want to test that your TOML file matches our schema quickly, you can use this command.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfd6df75627898873/6a7d811db4377024e84d3f6b/image_9.jpg" alt="Detection Rules CLI setup" title="Detection Rules CLI setup" /></p>
<p>After you have installed the package <a href="https://github.com/elastic/detection-rules#getting-started">dependencies</a> and your credential configuration, you’re ready to use the CLI. One of the cool things about using the CLI is the ability to download data while testing an RTA using the <code>collect-events</code> command.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta0a0b418fa28837d/6a7d811f6c6eac35e3f1135a/image_10.jpg" alt="Detection Rules CLI collect-events function" title="Detection Rules CLI collect-events function" /></p>
<p>Once you start collecting events, the CLI command will idle until you're ready to save events. While you wait, you have an opportunity to jump onto the target machine, execute an RTA, detonate a malware sample, or launch any payloads to trigger an alert. These events can be stored offline and reused later in an automated testing process. With the collect-events command, you can apply several options that scope your exports, like specifying the index and specific <a href="https://www.elastic.co/guide/en/ecs/current/ecs-host.html#field-host-id">host.id</a> of the target system you want. Once the command starts, it gathers all events associated with the host until you’re ready to stop the collection.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte739c5ffdc5a40b8/6a7d8122fc63ab27da649fbc/image6.gif" alt="Detection Rules CLI collect-events in action" title="Detection Rules CLI collect-events in action" /></p>
<p>As you can see, it’s possible to run the <code>collect-events</code> command, generate malicious activity on a target system (e.g., using an RTA), and download the events locally for review. Some users export and use these events as-is, but we intend to store these events to help automate and streamline our end-to-end testing process.</p>
<p>Apart from the <code>es</code> (Elasticsearch) function, we often use several other options like linting our ruleset with <code>toml-lint</code> , validating our rules with <code>validate-all</code> , or even surveying out ruleset against alerts with in-development commands buried deep within our dev CLI section like <code>rule-survey</code>. If you’re interested in reading more about the other fields available, see our guide on <a href="https://github.com/elastic/detection-rules/blob/main/CONTRIBUTING.md#creating-a-rule-with-the-cli">creating a rule with the CLI</a> or the <a href="https://github.com/elastic/detection-rules/blob/main/CLI.md">CLI.md</a>. As always, if you have any questions or need help, feel free to submit an issue.</p>
<p>Tools like the EQLPlaygound, RTAs, and detection-rules CLI are great resources for getting started with EQL, threat hunting, and detection engineering respectively. Coupled with the detection-rules CLI and RTAs, these tools give security research engineers immediate feedback to begin managing their custom Elastic detection rules. Whether you’re using a cloud Elastic Stack, a local deployment, or are setting up a lab environment with our newly released <a href="https://www.elastic.co/security-labs/the-elastic-container-project">Elastic Container Project</a>, we’ve got you covered. These are just a few tools we use that you're welcome to try out for your internal workflows, they help us test and create rules every day.</p>
<p>In a following article of TRaDE craft, we’ll describe how we validate our rules across languages like EQL or KQL, and how we automate our end-to-end process. Additionally, if you’re interested in hearing how our partners at Tines have integrated Elastic detection logic, check out their blog on <a href="https://www.tines.com/blog/automating-detection-as-code">Automating Detection-as-Code</a>, which walks through the Elastic SIEM, detection content development CI/CD, alert management, and response handling.</p>
<p>Update: RTAs have relocated to the <a href="https://github.com/elastic/cortado">Cortado</a> centralized repository which now has the option to use the packages RTAs whl available under <a href="https://github.com/elastic/cortado/releases">releases</a>.  See the <a href="https://github.com/elastic/cortado/blob/main/README.md">README</a> for more details.</p>
<p>We’re always interested in hearing use cases and workflows like these, so as always, reach out to us via <a href="https://github.com/elastic/protections-artifacts/issues">GitHub issues</a>, chat with us in our <a href="http://ela.st/slack">community Slack</a>, and ask questions in our <a href="https://discuss.elastic.co/c/security/endpoint-security/80">Discuss forums</a>!</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/handy-elastic-tools-for-the-enthusiastic-detection-engineer</link>
    <guid isPermaLink="false">handy-elastic-tools-for-the-enthusiastic-detection-engineer</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Mika Ayenson]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf4de479712cf375b/6a7d812551156ab10f2bf883/security-threat-monitoring-compliance-1200x628.jpg" length="0" type="image/jpeg"/>
    <pubDate>Mon, 12 Sep 2022 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Extracting Cobalt Strike Beacon Configurations]]></title>
    <description><![CDATA[Part 2 - Extracting configurations from Cobalt Strike implant beacons.]]></description>
    <content:encoded><![CDATA[<p>Please check out our <a href="https://www.elastic.co/security-labs/collecting-cobalt-strike-beacons-with-the-elastic-stack">previous post</a> on how to collect Cobalt Strike beacon implants. We'll build on that information to extract the configurations from the beacons.</p>
<p>In this post, we'll walk through manually analyzing a Cobalt Strike C2 configuration from a binary beacon payload using the excellent <a href="https://github.com/strozfriedberg/cobaltstrike-config-extractor">Cobalt Strike Configuration Extractor (CSCE)</a>. We'll also cover enabling some newer features of the Elastic Stack that will allow you to do this at scale across all your monitored endpoints, by extracting the beacons from memory.</p>
<blockquote>
  <p>The team at Blackberry has a tremendous handbook called “<a href="https://www.blackberry.com/us/en/forms/enterprise/ebook-beacons-in-the-dark">Finding Beacons in the Dark</a>” (registration required) that dives extensively into Cobalt Strike beacon configurations. We’ll discuss a few fields in the configurations here, but if you’re interested in learning about how beacons function, we strongly recommend checking that resource out.</p>
</blockquote>
<h2 id="cobaltstrikeconfigurationextractor">Cobalt Strike Configuration Extractor</h2>
<p>The <a href="https://github.com/strozfriedberg/cobaltstrike-config-extractor">Cobalt Strike Configuration Extractor (CSCE)</a> by Stroz Friedberg is a "python library and set of scripts to extract and parse configurations from Cobalt Strike beacons".</p>
<p>To use the CSCE, we'll create a Python virtual environment, activate it, and install the CSCE Python package.</p>
<h2 id="settingupthecobaltstrikeconfigurationextractor">Setting up the Cobalt Strike Configuration Extractor</h2>
<pre><code>$ python3 -m venv csce

$ source csce/bin/activate

(csce) $ pip3 install libcsce

...truncated...
Collecting libcsce
  Using cached libcsce-0.1.0-py3-none-any.whl (24 kB)
Collecting pefile&gt;=2019.4.18
...truncated...
</code></pre>
<p>Next, we can run the CSCE on the beacon payload we extracted from memory to see if there's any interesting information stored we can collect (we'll add the <code>--pretty</code> flag to make the output easier to read as a JSON document).</p>
<h2 id="viewingtheatomicindicatorsofthecsbeaconconfiguration">Viewing the atomic indicators of the CS beacon configuration</h2>
<pre><code>(csce) $ csce --pretty beacon.exe

{
  "beacontype": [
    "HTTPS"
  ],
  "sleeptime": 45000,
  "jitter": 37,
  "maxgetsize": 1403644,
  "spawnto": "GNEtW6h/g4dQzm0dOkL5NA==",
  "license_id": 334850267,
  "cfg_caution": false,
  "kill_date": "2021-12-24",
  "server": {
    "hostname": "clevelandclinic[.]cloud",
    "port": 443,
    "publickey": "MIGfMA0GCSqGSIb3DQEBAQUAA4G...
...truncated...
</code></pre>
<p>Immediately, we can see that the beacon uses HTTPS to communicate and that the domain is <code>clevelandclinic[.]cloud</code>. This gives us an atomic indicator that we can do some analysis on. Looking at the <a href="https://www.cobaltstrike.com/help-malleable-c2">Malleable Command and Control documentation</a>, we can get a description of the configuration variables.</p>
<p>As an example, we can see that the <code>sleeptime</code> is <code>450000</code> milliseconds, which changes the default beacon check in from every 60-seconds to 450-seconds, or 7 ½ minutes. Additionally, we see a jitter of <code>37</code> meaning that there is a random jitter of 37% of <code>450000</code> milliseconds (<code>166,500</code> milliseconds), so the beacon check-in could be between <code>283,000</code> and <code>450,000</code> milliseconds (4.7 - 7.5 minutes).</p>
<p>Additionally, the <code>publickey</code> field is used by the Cobalt Strike Team Server to encrypt communications between the server and the beacon. This is different from normal TLS certificates used when accessing the C2 domain with a browser or data-transfer libraries, like <code>cURL</code>. This field is of note because the Team Server uses the same publickey for each beacon, so this field is valuable in clustering beacons with their perspective Team Server because threat actors often use the same Team Server for multiple campaigns, so this data from the configuration can be used to link threat actors to multiple campaigns and infrastructure.</p>
<p>Continuing to look at the configuration output, we can see another interesting section around the <code>process-inject</code> nested field, <code>stub</code>:</p>
<h2 id="viewingtheprocessinjectstubfield">Viewing the process-inject.stub field</h2>
<pre><code>(csce) $ csce --pretty beacon.exe

...truncated...
  "process-inject": {
    "allocator": "NtMapViewOfSection",
    "execute": [
      "CreateThread 'ntdll!RtlUserThreadStart'",
      "CreateThread",
      "NtQueueApcThread-s",
      "CreateRemoteThread",
      "RtlCreateUserThread"
    ],
    "min_alloc": 17500,
    "startrwx": false,
    "stub": "IiuPJ9vfuo3dVZ7son6mSA==",
    "transform-x86": [
      "prepend '\\x90\\x90'"
    ],
...
</code></pre>
<p>The <code>stub</code> field contains the Base64 encoded MD5 file hash of the Cobalt Strike Java archive. To convert this, we can again use CyberChef, this time add the "From Base64" and "To Hex" <a href="https://gchq.github.io/CyberChef/#recipe=From_Base64('A-Za-z0-9%2B/%3D',true)To_Hex('None',0)">recipes</a>, ensure you change the "Delimiter" to "None" in the "To Hex" recipe.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9681dd02fd3d4324/6a7d805cea068d3cbcf07215/cyber-chef-md5.jpg" alt="" /></p>
<p>Now that we have the MD5 value of the Java archive (<code>222b8f27dbdfba8ddd559eeca27ea648</code>), we can check that against online databases like VirusTotal to get additional information, specifically, the SHA256 hash (<code>7af9c759ac78da920395debb443b9007fdf51fa66a48f0fbdaafb30b00a8a858</code>).</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfaec6363c8d0a9e8/6a7d805fbd21983d477552b3/cobaltstrike-jar-sha256.jpg" alt="" /></p>
<p>Finally, we can verify the SHA256 hash with CobaltStrike to identify the version of the Java archive by going to <a href="https://verify.cobaltstrike.com">https://verify.cobaltstrike.com</a> and searching for the hash.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2f4671076a55a527/6a7d806273d9bd805829abf9/cobaltstrike-jar-version.jpg" alt="" /></p>
<p>Now we know that this beacon was created using a licensed version of Cobalt Strike 4.4.</p>
<p>Another field from the configuration that is helpful in clustering activity is the <code>license_id</code> field.</p>
<h2 id="viewingcobaltstrikewatermark">Viewing Cobalt Strike watermark</h2>
<pre><code>...truncated
  "spawnto": "GNEtW6h/g4dQzm0dOkL5NA==",
  "license_id": 334850267,
  "cfg_caution": false,
...truncated...
</code></pre>
<p>This is commonly referred to as the Watermark and is a 9-digit value that is unique per license. While this value can be modified, it can still be used in conjunction with the <code>process-inject.stub</code> and <code>publickey</code> fields (discussed above) to cluster infrastructure and activity groups.</p>
<p>These are just a few fields that can be used to identify and cluster activities using configurations extracted from the Cobalt Strike beacon. If you're interested in a very in-depth analysis of the configuration, we recommend you check out the <a href="https://www.blackberry.com/us/en/forms/enterprise/ebook-beacons-in-the-dark">Finding Beacons in the Dark Cobalt Strike handbook by the team at Blackberry</a>.</p>
<h2 id="puttinganalysistoaction">Putting Analysis to Action</h2>
<p>To test out our analyst playbook for collecting Cobalt Strike beacon payloads, their configurations, and metadata contained within; we can apply those to more data to identify clusters of activity.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt31275932be8848d4/6a7d8064e88c6584bc008962/maltego.jpg" alt="" /></p>
<p>In the above illustration, we can cluster threat actors based on their shared uses of the beacon payload public key, which as we described above, is unique per Team Server. This would allow us to group multiple beacon payload hashes, infrastructure, and campaigns to a single Threat Actor.</p>
<p>As always, using the atomic indicators extracted from the beacon payload configurations (<code>clevelandclinic[.]cloud</code> in our example) allow you to identify additional shared infrastructure, target verticals, and threat actor capabilities.</p>
<h3 id="thistimeatfullspeed">This time at full speed</h3>
<p>All of the steps that we've highlighted in this release, as well as the <a href="https://www.elastic.co/security-labs/collecting-cobalt-strike-beacons-with-the-elastic-stack">previous release</a>, can be automated and written into Elasticsearch using the <a href="https://www.elastic.co/security-labs/cobalt-strike-beacon-extractor">Cobalt Strike Beacon Extraction</a> project.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbfa6eeded69b2af2/6a7d806796b5a6eead878629/cs-to-elasticsearch.jpg" alt="" /></p>
<h2 id="summary">Summary</h2>
<p>In this post, we highlighted new features in the Elastic Stack that can be used to collect Cobalt Strike Malleable C2 beacon payloads. Additionally, we covered the processes to build Fleet policies to extract beacon payloads from memory and their configurations.</p>
<p>These Fleet policies and processes enable security analysts to collect Cobalt Strike beacon payloads and their configurations to identify threat actor controlled infrastructure and cluster activity.</p>
<h2 id="artifacts">Artifacts</h2>
<p>Observable | Type | Note -------------------------------------------------------------------|-------------|------------------------------------------ <code>697fddfc5195828777622236f2b133c0a24a6d0dc539ae7da41798c4456a3f89</code> | SHA256 | Cobalt Strike Malleable C2 beacon payload <code>7475a6c08fa90e7af36fd7aa76be6e06b9e887bc0a6501914688a87a43ac7ac4</code> | SHA256 | Cobalt Strike Malleable C2 beacon payload <code>f9b38c422a89d73ebdab7c142c8920690ee3a746fc4eea9175d745183c946fc5</code> | SHA256 | Cobalt Strike Malleable C2 beacon payload <code>clevelandclinic[.]cloud</code> | domain-name | Cobalt Strike Malleable C2 domain <code>104[.]197[.]142[.]19</code> | ipv4-addr | Cobalt Strike Malleable C2 IP address <code>192[.]64[.]119[.]19</code> | ipv4-addr | Cobalt Strike Malleable C2 IP address</p>
<h2 id="artifacts-1">Artifacts</h2>
<p>Artifacts are also available for <a href="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9ba95a979c5a3026/628e88d904574953584774c8/extracting-cobalt-strike-indicators.zip">download</a> in both ECS and STIX format in a combined zip bundle.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/extracting-cobalt-strike-beacon-configurations</link>
    <guid isPermaLink="false">extracting-cobalt-strike-beacon-configurations</guid>
    <category><![CDATA[Integrations & Tools]]></category>
    <dc:creator><![CDATA[Daniel Stepanic,Derek Ditch,Seth Goodwin,Andrew Pease]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt38f8bee3ce611c76/6a7d806b437e0f3009dd85b6/photo-edited-03@2x.jpg" length="0" type="image/jpeg"/>
    <pubDate>Fri, 09 Sep 2022 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>