<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Elastic Security Labs - Tools</title>
        <link>https://www.elastic.co/security-labs</link>
        <description>Trusted security news &amp; research from the team at Elastic.</description>
        <lastBuildDate>Sat, 11 Jul 2026 12:39:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Elastic Security Labs - Tools</title>
            <url>https://www.elastic.co/security-labs/assets/security-labs-thumbnail.png</url>
            <link>https://www.elastic.co/security-labs</link>
        </image>
        <copyright>© 2026. elasticsearch B.V. All Rights Reserved</copyright>
        <item>
            <title><![CDATA[CI/CD pipeline abuse: the problem no one is watching]]></title>
            <link>https://www.elastic.co/security-labs/detecting-cicd-pipeline-abuse-with-llm-augmented-analysis</link>
            <guid>detecting-cicd-pipeline-abuse-with-llm-augmented-analysis</guid>
            <pubDate>Wed, 29 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[How we built an open-source, drop-in CI template that uses signal extraction and LLM reasoning to catch CI/CD abuse in GitHub Actions, GitLab CI, and Azure DevOps pipelines.]]></description>
            <content:encoded><![CDATA[<h2>Preamble</h2>
<p>In 2025 and 2026, we watched a pattern play out across the industry. Attackers stopped going after production servers directly and started targeting the automation that deploys to them. Compromised developer credentials, a modified workflow file, and suddenly every secret in a CI/CD environment is streaming to an attacker-controlled endpoint. We saw this play out across incidents involving <a href="https://blog.gitguardian.com/ghostaction-campaign-3-325-secrets-stolen">major open-source projects</a>, <a href="https://orca.security/resources/blog/pull-request-nightmare-github-actions-rce/">Fortune 500 companies</a>, and <a href="https://about.codecov.io/apr-2021-post-mortem/">critical infrastructure tooling</a>.</p>
<p>The attack chain is deceptively simple:</p>
<p>Stolen developer credentials → Modified workflow file → Harvested CI secrets → Lateral movement to cloud and production</p>
<p>Today we are open-sourcing <a href="https://github.com/elastic/cicd-abuse-detector">cicd-abuse-detector</a>, a drop-in CI template that uses regex-based signal extraction and LLM analysis to detect suspicious changes to CI/CD pipelines. It works across GitHub Actions, GitLab CI, and Azure DevOps, and is designed around the real-world attack techniques documented in public security research.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/detecting-cicd-pipeline-abuse-with-llm-augmented-analysis/image4.png" alt="CI/CD Abuse Detector execution flow" title="CI/CD Abuse Detector execution flow" /></p>
<h2>Key takeaways</h2>
<ul>
<li>CI/CD environments are high-value targets because a single compromised workflow can exfiltrate cloud credentials, package registry tokens, code signing keys, deploy keys, and OIDC tokens simultaneously</li>
<li>The tool extracts 50+ regex and metadata signals from diffs, then passes them with the full diff to Claude for structured threat analysis. No Python, no dependencies beyond bash and the Claude Code CLI</li>
<li>Detection patterns were tested against offensive toolkits like <a href="https://github.com/synacktiv/nord-stream">Nord Stream</a> and <a href="https://github.com/AdnaneKhan/Gato-X">Gato-X</a>, and against real incidents including <a href="https://unit42.paloaltonetworks.com/github-repo-artifacts-leak-tokens/">ArtiPACKED</a> and <a href="https://orca.security/resources/blog/hackerbot-claw-github-actions-attack/">HackerBot-Claw</a></li>
<li>The project ships with 19 malicious and four benign example diffs modeled after specific incidents, and an automated test suite that validates every signal</li>
</ul>
<h2>Why CI/CD pipelines are a top target</h2>
<p>If you spend time reviewing GitHub Actions or GitLab CI configurations, you might notice how much trust is concentrated in these files. A typical deployment workflow has access to AWS credentials, npm publish tokens, Docker Hub passwords, and a GitHub token with write permissions, all at the same time. The attack surface isn't a server with a CVE, it's a YAML file.</p>
<h3>Credential harvesting at scale</h3>
<p>An attacker with stolen developer credentials modifies a workflow to exfiltrate secrets available in the CI environment. The <a href="https://blog.gitguardian.com/ghostaction-campaign-3-325-secrets-stolen">GhostAction campaign</a> in September 2025 demonstrated this at scale, compromising 327 GitHub users across 817 repositories. 3,325 secrets were stolen through injected workflow files that POST'd credentials to attacker endpoints.</p>
<p>The <a href="https://www.reversinglabs.com/blog/shai-hulud-worm-npm">Shai-Hulud npm worm</a> went further. This self-propagating attack harvested GitHub Personal Access Tokens via gh auth token, ran <a href="https://github.com/trufflesecurity/trufflehog">TruffleHog</a> for secret reconnaissance, and used compromised tokens to silently inject malicious code into other packages owned by the same developer. Over 46,000 malicious packages were published in the first wave alone.</p>
<h3>Privileged trigger exploitation</h3>
<p>The pull_request_target trigger is one of the most dangerous features in GitHub Actions. Unlike a regular pull_request trigger, it runs workflows in the context of the base repository with access to secrets, but it can execute code from an untrusted fork. The <a href="https://orca.security/resources/blog/pull-request-nightmare-github-actions-rce/">Orca &quot;Pull Request Nightmare&quot;</a> research demonstrated this against repositories maintained by Google, Microsoft, and NVIDIA.</p>
<p>In February 2026, an automated campaign called <a href="https://www.stepsecurity.io/blog/hackerbot-claw-github-actions-exploitation">HackerBot-Claw</a> systematically scanned public repositories for this exact misconfiguration. It used five different exploitation techniques, including poisoned Go <code>init()</code> functions, branch name command injection, filename-based injection, direct script injection, and AI prompt injection against Claude-based code reviewers. In the most severe case, Aqua Security's Trivy repository was fully compromised, leading to a downstream supply chain attack that exposed 33,000 secrets across nearly 7,000 machines. As <a href="https://www.microsoft.com/en-us/security/blog/2026/03/24/detecting-investigating-defending-against-trivy-supply-chain-compromise/">documented</a>, this supply chain attack was made possible with compromised tokens that were valid weeks after initially stolen.</p>
<h3>The rest of the taxonomy</h3>
<p>Beyond credential harvesting and trigger exploitation, the threat model covers four additional categories that appear consistently in public research:</p>
<ul>
<li>Permission escalation, where adding permissions: write-all or id-token: write broadens the blast radius of any compromise</li>
<li>Runner targeting, redirecting jobs to self-hosted runners that often have network access to internal infrastructure, or specifying attacker-controlled container images</li>
<li>Supply chain manipulation through mutable action references (using @main instead of SHA-pinned versions), remote script execution (<code>curl</code> | <code>bash</code>), lockfile registry swaps, and dependency poisoning</li>
<li>Defense evasion via commit timestamp manipulation, making malicious files appear old and trusted. <a href="https://kl4r10n.tech/blog/when-git-history-lies">KL4R10N documented</a> this technique in DPRK-linked campaigns where backdated commits reference infrastructure that did not exist at the claimed date</li>
</ul>
<p>Each of these maps to specific <a href="https://attack.mitre.org/">MITRE ATT&amp;CK</a> techniques: <a href="https://attack.mitre.org/techniques/T1552/">T1552</a> (Unsecured Credentials), <a href="https://attack.mitre.org/techniques/T1195/">T1195</a> (Supply Chain Compromise), <a href="https://attack.mitre.org/techniques/T1070/006/">T1070.006</a> (Timestomp), and <a href="https://attack.mitre.org/techniques/T1059/">T1059</a> (Command and Scripting Interpreter).</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/detecting-cicd-pipeline-abuse-with-llm-augmented-analysis/image1.png" alt="CI/CD Abuse Detector attack taxonomy and detection paths" title="CI/CD Abuse Detector attack taxonomy and detection paths" /></p>
<h2>How the detector works</h2>
<p>We wanted the templates to work without requiring Python, custom runtimes, or complex dependencies. Everything runs in standard shell utilities on a default ubuntu-latest runner, and the only installed tool is the <a href="https://docs.anthropic.com/en/docs/claude-code">Claude Code CLI</a> via npm, which handles authentication, retries, and model routing.</p>
<h3>Stage 1: Filter and diff</h3>
<p>When a pull request is opened (or a push lands on a protected branch), the workflow identifies changed files across three tiers of CI/CD-relevant paths. The first tier covers core CI files like workflow definitions, pipeline configs, and Makefiles. The second covers build and release artifacts like Dockerfiles, package manifests, lockfiles, and signing or deploy scripts. The third tier picks up developer environment configs like .vscode/tasks.json and .devcontainer files.</p>
<p>Each file is diffed individually and capped at 10,000 characters. We do this per-file rather than globally because a single cap on the combined diff is a bypass vector. An attacker can pad a malicious workflow change with a large benign Dockerfile edit to push the exploit past the character limit.</p>
<h3>Stage 2: Signal extraction</h3>
<p>Before the LLM sees anything, 50+ regex patterns scan each diff for known-dangerous patterns. These signals are advisory. They never gate the analysis, but they provide the LLM with a pre-screened threat summary. A few examples:</p>
<table>
<thead>
<tr>
<th align="left">Signal</th>
<th align="left">Pattern</th>
<th align="left">What it catches</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><code>secrets_context</code></td>
<td align="left"><code>${{.*secrets.</code></td>
<td align="left">Direct secret interpolation in workflows</td>
</tr>
<tr>
<td align="left"><code>pull_request_target</code></td>
<td align="left"><code>pull_request_target</code></td>
<td align="left">The dangerous trigger that grants secrets to PR code</td>
</tr>
<tr>
<td align="left"><code>checkout_ref</code></td>
<td align="left"><code>ref:.*github.event.pull_request.head.(sha|ref)</code></td>
<td align="left">Untrusted PR code checked out in a privileged context</td>
</tr>
<tr>
<td align="left"><code>double_base64</code></td>
<td align="left"><code>base64.*|.*base64</code></td>
<td align="left">Double-encoding to evade log masking (Nord Stream technique)</td>
</tr>
<tr>
<td align="left"><code>ld_preload</code></td>
<td align="left"><code>LD_PRELOAD</code></td>
<td align="left">Arbitrary code execution via environment variable injection</td>
</tr>
<tr>
<td align="left"><code>vscode_auto_task</code></td>
<td align="left"><code>runOn.*folderOpen</code></td>
<td align="left">VS Code task that executes on folder open (Contagious Interview)</td>
</tr>
</tbody>
</table>
<p>The signal list is based on real adversarial tooling, including <a href="https://github.com/synacktiv/nord-stream">Nord Stream</a> and <a href="https://github.com/AdnaneKhan/Gato-X">Gato-X</a>, and tested against 19 malicious example diffs modeled after specific incidents.</p>
<p>The detector runs identically across GitHub Actions, GitLab CI, and Azure DevOps. Here are detections firing on each platform:</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/detecting-cicd-pipeline-abuse-with-llm-augmented-analysis/image8.png" alt="GitHub CI/CD Abuse Detector alert" title="GitHub CI/CD Abuse Detector alert" /></p>
<p><img src="https://www.elastic.co/security-labs/assets/images/detecting-cicd-pipeline-abuse-with-llm-augmented-analysis/image7.png" alt="GitLab CI/CD Abuse Detector alert" title="GitLab CI/CD Abuse Detector alert" /></p>
<p><img src="https://www.elastic.co/security-labs/assets/images/detecting-cicd-pipeline-abuse-with-llm-augmented-analysis/image2.png" alt="Azure DevOps CI/CD Abuse Detector alert" title="Azure DevOps CI/CD Abuse Detector alert" /></p>
<h3>Stage 3: LLM analysis</h3>
<p>The signal summary, full diff, author profile, and commit metadata are bundled and sent to Claude via the Claude Code CLI. The <a href="https://github.com/elastic/cicd-abuse-detector/blob/main/prompts/analyze-cicd-change.md">analysis prompt</a> walks the model through several areas:</p>
<ol>
<li>Diff comprehension and per-file risk assessment</li>
<li>Signal interpretation with context (a signal alone is not a verdict)</li>
<li>Temporal analysis for backdated commits</li>
<li>Author trust assessment using account age, contribution history, and org membership</li>
<li>Severity calibration against a signal combination table with 60+ entries</li>
<li>False positive recognition (e.g., cURL for downloading known tools is not exfiltration)</li>
<li>Concrete, actionable recommendations (&quot;Pin actions/setup-node@main to a specific SHA&quot; instead of &quot;review carefully&quot;)</li>
</ol>
<p>The output is a structured JSON verdict containing severity, confidence, reasoning, evidence, and recommendations, all validated against a <a href="https://github.com/elastic/cicd-abuse-detector/blob/main/schemas/verdict.schema.json">JSON Schema</a>.</p>
<h3>Stage 4: Alert and gate</h3>
<p>Based on the verdict severity, the workflow posts a step summary, creates an issue, sends a Slack notification, and optionally fails the PR check if severity meets a configured threshold.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/detecting-cicd-pipeline-abuse-with-llm-augmented-analysis/image3.png" alt="Slack notification from the CI/CD Abuse Detector flagging a critical severity finding" title="Slack notification from the CI/CD Abuse Detector flagging a critical severity finding" /></p>
<p><img src="https://www.elastic.co/security-labs/assets/images/detecting-cicd-pipeline-abuse-with-llm-augmented-analysis/image6.png" alt="Shipping verdicts to Elastic" title="Shipping verdicts to Elastic" /></p>
<p>Alerts in Slack and GitHub Issues solve the immediate notification problem, but they don't give you a queryable history. Every verdict the detector produces (e.g. benign, suspicious, or malicious), can optionally ship to Elasticsearch as a structured document in the logs-cicd.abuse-default data stream. The workflow ships the verdict along with CI/CD metadata (platform, repository, actor, event type, run URL) into a single index that spans all three supported platforms.</p>
<p>This is where cross-platform correlation becomes practical. A GitHub Actions alert and a GitLab CI alert from the same actor land in the same data stream, queryable in a single ES|QL statement:</p>
<pre><code class="language-sql">FROM logs-cicd.abuse-* 
WHERE verdict.verdict IN (&quot;malicious&quot;, &quot;suspicious&quot;) AND @timestamp &gt; NOW() - 7 days 
EVAL platform = cicd.platform, repo = cicd.repository, actor = cicd.actor, severity = verdict.severity
KEEP @timestamp, platform, repo, actor, severity
SORT @timestamp DESC
</code></pre>
<p><img src="https://www.elastic.co/security-labs/assets/images/detecting-cicd-pipeline-abuse-with-llm-augmented-analysis/image5.png" alt="Cross Platform Verdicts From GitHub Actions, GitLab CI, Azure DevOps Pipelines" title="Cross Platform Verdicts From GitHub Actions, GitLab CI, Azure DevOps Pipelines" /></p>
<p>The schema includes  cicd.platform, cicd.repository, cicd.actor, and the full verdict object (verdict, severity, confidence, summary, reasons, evidence), making it straightforward to build detection rules. A coordinated campaign that hits multiple repos within an hour, a repeat offender flagged across platforms, or a spike in critical findings that warrants an incident response page can be correlated.</p>
<h2>Validating against real attacks</h2>
<p>To validate coverage, we compared our detection patterns against the actual source code of offensive tools, published research, and public post-mortems.</p>
<h3>Nord Stream: verbatim payload matching</h3>
<p>Nord Stream is Synacktiv's open-source CI/CD secret extraction tool supporting GitHub, GitLab, and Azure DevOps. We pulled the YAML generator source (<code>nordstream/yaml/github.py</code>) and compared its output templates against our example diffs.</p>
<ul>
<li>The GitHub payload template uses <code>env -0 | awk -v RS='0' '/^secret_/ {print $0}' | base64 -w0 | base64 -w0</code>. Our <code>nord-stream-pipeline-exfil.diff</code> contains this line verbatim, and our <code>double_base64</code>, <code>env_null_dump</code>, and <code>env_secret_grep</code> signals all fire.</li>
<li>The OIDC Azure template uses <code>azure/login@v1</code> with <code>id-token: write</code> permissions followed by az account <code>get-access-token | base64 -w0 | base64 -w0</code>. Our diff captures this exact flow and triggers <code>cloud_auth_action</code> and <code>id_token_write</code>.</li>
<li>The Azure DevOps pipeline techniques (<code>addSpnToEnvironment</code> for SPN credential exposure, <code>DownloadSecureFile</code> for secure file theft, SSH task source patching via <code>ssh.js</code> modification) are all present in <code>nord-stream-azure-devops.diff</code> and detected by platform-specific signals.</li>
</ul>
<h3>ArtiPACKED: the artifact race condition</h3>
<p>The <a href="https://unit42.paloaltonetworks.com/github-repo-artifacts-leak-tokens/">ArtiPACKED</a> research from Palo Alto Unit 42 showed that uploading the entire checkout directory as an artifact leaks the <code>.git/config</code> file containing the <code>GITHUB_TOKEN</code>. With the v4 artifact API allowing mid-run downloads, an attacker can extract and use the token before the job completes.</p>
<p>Our <code>artifact-token-leak.diff</code> models this exact pattern, using <code>upload-artifact</code> with <code>path: .</code> (the entire workspace). The <code>upload_artifact</code> signal catches it, and the LLM evaluates whether the upload scope includes the <code>.git</code> directory.</p>
<h3>GITHUB_ENV injection: LD_PRELOAD to RCE</h3>
<p><a href="https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0">Legit Security's research</a> on Google Firebase and Apache showed that writing untrusted input to <code>$GITHUB_ENV</code> allows an attacker to set arbitrary environment variables like <code>LD_PRELOAD</code> and <code>NODE_OPTIONS</code>, achieving code execution in privileged workflows.</p>
<p>Our <code>github-env-injection.diff</code> reproduces this technique with three distinct payloads, including <code>LD_PRELOAD</code> pointing to a malicious shared object, <code>NODE_OPTIONS</code> with a required injection, and $<code>GITHUB_PATH</code> manipulation. The <code>github_env_write</code>, <code>ld_preload</code>, and <code>github_path_write</code> signals all trigger as expected.</p>
<h3>Contagious Interview: IDE config as initial access</h3>
<p>The <a href="https://www.abstract.security/blog/contagious-interview-tracking-the-vs-code-tasks-infection-vector">Contagious Interview campaign</a> attributed to DPRK targets developers through fake job interviews, distributing repositories with <code>.vscode/tasks.json</code> files that auto-execute on folder open. The presentation is hidden (<code>reveal: never</code>, <code>echo: false</code>), and the payload uses <code>curl</code> | <code>node</code> for silent execution.</p>
<p>Our <code>ide-config-poisoning.diff</code> captures the full attack chain, including the auto-execute trigger (<code>runOn: folderOpen</code>), the hidden presentation, the <code>curl | node</code> payload, the <code>files.exclude</code> entry that hides the <code>.vscode</code> directory, and a trojanized postinstall hook with base64-encoded URLs and <code>eval()</code> for code execution. Six signals pick this up at once.</p>
<h2>Defensive recommendations</h2>
<p>Beyond deploying the detector, here are some hardening measures that came directly out of the attack patterns we studied:</p>
<ul>
<li>Pin all actions to SHA, not tags, not branches. SHA-pinned references prevent retroactive tag modification attacks like <code>tj-actions</code> (CVE-2025-30066).</li>
<li>Scope secrets to individual steps rather than using job-level environment variables. Each step should only have access to the secrets it actually needs.</li>
<li>Use short lived, ephemeral tokens when possible to reduce attack surface</li>
<li>Avoid <code>pull_request_target</code> unless strictly necessary. If you must use it, never checkout the PR head code in the same workflow. Use a separate <code>workflow_run-triggered workflow</code> for operations that need both secrets and PR context.</li>
<li>Set explicit permissions on every workflow because the default token permissions are far too broad. Set <code>permissions: {}</code> at the workflow level and add specific permissions per job.</li>
<li>Enable <code>persist-credentials: false</code> on checkout since the default behavior of actions/checkout persists the <code>GITHUB_TOKEN</code> in the <code>.git</code> directory. If you upload artifacts, this token goes with them.</li>
</ul>
<h2>Summary</h2>
<p>CI/CD pipelines have become a major attack surface for supply chain compromise. The same automation that makes modern software delivery possible is what attackers exploit to harvest credentials, poison packages, and pivot to cloud infrastructure. Traditional code review doesn't catch these patterns well because they're subtle, platform-specific, and designed to look like legitimate DevOps changes.</p>
<p>Combining regex-based signal extraction with LLM reasoning lets us surface these patterns at the pull request stage, before they reach production. The repo includes the full threat model, test suite, and example diffs if you want to dig into the details or adapt it to your own environment.</p>
<p>To get started, check out the <a href="https://github.com/elastic/cicd-abuse-detector">cicd-abuse-detector repo</a> for setup instructions, the full threat model, and example diffs. We're always interested in hearing about new attack patterns and detection ideas. Chat with us in our <a href="http://ela.st/slack">community Slack</a>, and ask questions in our <a href="https://discuss.elastic.co/c/security/endpoint-security/80">Discuss forums</a>.</p>
<h2>CI/CD abuse through MITRE ATT&amp;CK</h2>
<p>We use the <a href="https://attack.mitre.org/">MITRE ATT&amp;CK</a> framework to map the tactics, techniques, and procedures that adversaries use against CI/CD pipelines.</p>
<h3>Tactics</h3>
<table>
<thead>
<tr>
<th align="left">Tactic</th>
<th align="left">CI/CD Relevance</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><a href="https://attack.mitre.org/tactics/TA0006/">Credential Access (TA0006)</a></td>
<td align="left">Harvesting secrets from CI environments</td>
</tr>
<tr>
<td align="left"><a href="https://attack.mitre.org/tactics/TA0002/">Execution (TA0002)</a></td>
<td align="left">Running commands in pipeline runners</td>
</tr>
<tr>
<td align="left"><a href="https://attack.mitre.org/tactics/TA0003/">Persistence (TA0003)</a></td>
<td align="left">Scheduled triggers, cron-based workflows</td>
</tr>
<tr>
<td align="left"><a href="https://attack.mitre.org/tactics/TA0005/">Defense Evasion (TA0005)</a></td>
<td align="left">Commit timestamp manipulation, log masking evasion</td>
</tr>
<tr>
<td align="left"><a href="https://attack.mitre.org/tactics/TA0001/">Initial Access (TA0001)</a></td>
<td align="left">Compromised developer credentials, phishing for PATs</td>
</tr>
<tr>
<td align="left"><a href="https://attack.mitre.org/tactics/TA0008/">Lateral Movement (TA0008)</a></td>
<td align="left">Using harvested cloud credentials to pivot</td>
</tr>
</tbody>
</table>
<h3>Techniques</h3>
<table>
<thead>
<tr>
<th align="left">Technique</th>
<th align="left">CI/CD Application</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><a href="https://attack.mitre.org/techniques/T1552/">T1552: Unsecured Credentials</a></td>
<td align="left">Secrets exposed in CI environment variables, artifacts, and runner memory</td>
</tr>
<tr>
<td align="left"><a href="https://attack.mitre.org/techniques/T1195/002/">T1195.002: Compromise Software Supply Chain</a></td>
<td align="left">Poisoned actions, dependencies, and lockfiles</td>
</tr>
<tr>
<td align="left"><a href="https://attack.mitre.org/techniques/T1059/">T1059: Command and Scripting Interpreter</a></td>
<td align="left">curl</td>
</tr>
<tr>
<td align="left"><a href="https://attack.mitre.org/techniques/T1070/006/">T1070.006: Timestomp</a></td>
<td align="left">Backdated commit dates to evade review</td>
</tr>
<tr>
<td align="left"><a href="https://attack.mitre.org/techniques/T1098/">T1098: Account Manipulation</a></td>
<td align="left">Permission escalation via write-all, id-token: write</td>
</tr>
<tr>
<td align="left"><a href="https://attack.mitre.org/techniques/T1078/">T1078: Valid Accounts</a></td>
<td align="left">Stolen developer PATs used to modify workflows</td>
</tr>
</tbody>
</table>
<h2>References</h2>
<p>The following were referenced throughout the above research:</p>
<ul>
<li><a href="https://github.com/elastic/cicd-abuse-detector">https://github.com/elastic/cicd-abuse-detector</a></li>
<li><a href="https://github.com/synacktiv/nord-stream">https://github.com/synacktiv/nord-stream</a></li>
<li><a href="https://github.com/AdnaneKhan/Gato-X">https://github.com/AdnaneKhan/Gato-X</a></li>
<li><a href="https://unit42.paloaltonetworks.com/github-repo-artifacts-leak-tokens/">https://unit42.paloaltonetworks.com/github-repo-artifacts-leak-tokens/</a></li>
<li><a href="https://blog.gitguardian.com/ghostaction-campaign-3-325-secrets-stolen">https://blog.gitguardian.com/ghostaction-campaign-3-325-secrets-stolen</a></li>
<li><a href="https://www.reversinglabs.com/blog/shai-hulud-worm-npm">https://www.reversinglabs.com/blog/shai-hulud-worm-npm</a></li>
<li><a href="https://orca.security/resources/blog/pull-request-nightmare-github-actions-rce/">https://orca.security/resources/blog/pull-request-nightmare-github-actions-rce/</a></li>
<li><a href="https://orca.security/resources/blog/hackerbot-claw-github-actions-attack/">https://orca.security/resources/blog/hackerbot-claw-github-actions-attack/</a></li>
<li><a href="https://www.stepsecurity.io/blog/hackerbot-claw-github-actions-exploitation">https://www.stepsecurity.io/blog/hackerbot-claw-github-actions-exploitation</a></li>
<li><a href="https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0">https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0</a></li>
<li><a href="https://www.abstract.security/blog/contagious-interview-tracking-the-vs-code-tasks-infection-vector">https://www.abstract.security/blog/contagious-interview-tracking-the-vs-code-tasks-infection-vector</a></li>
<li><a href="https://about.codecov.io/apr-2021-post-mortem/">https://about.codecov.io/apr-2021-post-mortem/</a></li>
<li><a href="https://kl4r10n.tech/blog/when-git-history-lies">https://kl4r10n.tech/blog/when-git-history-lies</a></li>
<li><a href="https://www.synacktiv.com/en/publications/github-actions-exploitation-dependabot">https://www.synacktiv.com/en/publications/github-actions-exploitation-dependabot</a></li>
<li><a href="https://docs.anthropic.com/en/docs/claude-code">https://docs.anthropic.com/en/docs/claude-code</a></li>
</ul>
<h2>About Elastic Security Labs</h2>
<p>Elastic Security Labs is the threat intelligence branch of Elastic Security dedicated to creating positive change in the threat landscape. Elastic Security Labs provides publicly available research on emerging threats with an analysis of strategic, operational, and tactical adversary objectives, then integrates that research with the built-in detection and response capabilities of Elastic Security.</p>
<p>Follow Elastic Security Labs on Twitter <a href="https://twitter.com/elasticseclabs?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor">@elasticseclabs</a> and check out our research at <a href="https://www.elastic.co/security-labs/">www.elastic.co/security-labs/</a>.</p>]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/security-labs/assets/images/detecting-cicd-pipeline-abuse-with-llm-augmented-analysis/detecting-cicd-pipeline-abuse-with-llm-augmented-analysis.webp" length="0" type="image/webp"/>
        </item>
        <item>
            <title><![CDATA[WinVisor – A hypervisor-based emulator for Windows x64 user-mode executables]]></title>
            <link>https://www.elastic.co/security-labs/winvisor-hypervisor-based-emulator</link>
            <guid>winvisor-hypervisor-based-emulator</guid>
            <pubDate>Fri, 24 Jan 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[WinVisor is a hypervisor-based emulator for Windows x64 user-mode executables that leverages the Windows Hypervisor Platform API to provide a virtualized environment for logging syscalls and enabling memory introspection.]]></description>
            <content:encoded><![CDATA[<h2>Background</h2>
<p>In Windows 10 (version RS4), Microsoft introduced the <a href="https://learn.microsoft.com/en-us/virtualization/api/hypervisor-platform/hypervisor-platform">Windows Hypervisor Platform</a> (WHP) API. This API exposes Microsoft's built-in hypervisor functionality to user-mode Windows applications. In 2024, the author used this API to create a personal project: a 16-bit MS-DOS emulator called <a href="https://github.com/x86matthew/DOSVisor">DOSVisor</a>. As mentioned in the release notes, there have always been plans to take this concept further and use it to emulate Windows applications. Elastic provides a research week (ON Week) twice per year for staff to work on personal projects, providing a great opportunity to begin working on this project. This project will be (unimaginatively) named WinVisor, inspired by its DOSVisor predecessor.</p>
<p>Hypervisors provide hardware-level virtualization, eliminating the need to emulate the CPU via software. This ensures that instructions are executed exactly as they would be on a physical CPU, whereas software-based emulators often behave inconsistently in edge cases.</p>
<p>This project aims to build a virtual environment for executing Windows x64 binaries, allowing syscalls to be logged (or hooked) and enabling memory introspection. The goal of this project is not to build a comprehensive and secure sandbox - by default, all syscalls will simply be logged and forwarded directly to the host. In its initial form, it will be trivial for code running within the virtualized guest to &quot;escape&quot; to the host. Safely securing a sandbox is a difficult task, and is beyond the scope of this project. The limitations will be described in further detail at the end of the article.</p>
<p>Despite having been available for 6 years (at the time of writing), it seems that the WHP API hasn’t been used in many public projects other than complex codebases such as <a href="https://github.com/qemu/qemu">QEMU</a> and <a href="https://www.virtualbox.org/">VirtualBox</a>. One other notable project is Alex Ionescu's <a href="https://github.com/ionescu007/Simpleator">Simpleator</a> - a lightweight Windows user-mode emulator that also utilizes the WHP API. This project has many of the same goals as WinVisor, although the approach for implementation is quite different. The WinVisor project aims to automate as much as possible and support simple executables (e.g. <code>ping.exe</code>) universally out of the box.</p>
<p>This article will cover the general design of the project, some of the issues that were encountered, and how they were worked through. Some features will be limited due to development time constraints, but the final product will at least be a usable proof-of-concept. Links to the source code and binaries hosted on GitHub will be provided at the end of the article.</p>
<h3>Hypervisor basics</h3>
<p>Hypervisors are powered by VT-x (Intel) and AMD-V (AMD) extensions. These hardware-assisted frameworks enable virtualization by allowing one or more virtual machines to run on a single physical CPU. These extensions use different instruction sets and, therefore, are not inherently compatible with each other; separate code must be written for each.</p>
<p>Internally, Hyper-V uses <code>hvix64.exe</code> for Intel support and <code>hvax64.exe</code> for AMD support. Microsoft's WHP API abstracts these hardware differences, allowing applications to create and manage virtual partitions regardless of the underlying CPU type. For simplicity, the following explanation will focus solely on VT-x.</p>
<p>VT-x adds an additional set of instructions known as VMX (Virtual Machine Extensions), containing instructions such as <code>VMLAUNCH</code>, which begins the execution of a VM for the first time, and <code>VMRESUME</code>, which re-enters the VM after a VM exit. A VM exit occurs when certain conditions are triggered by the guest, such as specific instructions, I/O port access, page faults, and other exceptions.</p>
<p>Central to VMX is the Virtual Machine Control Structure (VMCS), a per-VM data structure that stores the state of the guest and host contexts as well as information about the execution environment. The VMCS contains fields that define processor state, control configurations, and optional conditions that trigger transitions from the guest back to the host. VMCS fields can be read or written to using the <code>VMREAD</code> and <code>VMWRITE</code> instructions.</p>
<p>During a VM exit, the processor saves the guest state in the VMCS and transitions back to the host state for hypervisor intervention.</p>
<h2>WinVisor overview</h2>
<p>This project takes advantage of the high-level nature of the WHP API. The API exposes hypervisor functionality to user-mode and allows applications to map virtual memory from the host process directly into the guest's physical memory.</p>
<p>The virtual CPU operates almost exclusively in CPL3 (user-mode), except for a small bootloader that runs at CPL0 (kernel-mode) to initialize the CPU state before execution. This will be described in further detail in the Virtual CPU section.</p>
<p>Building up the memory space for an emulated guest environment involves mapping the target executable and all DLL dependencies, followed by populating other internal data structures such as the Process Environment Block (PEB), Thread Environment Block (TEB), <code>KUSER_SHARED_DATA</code>, etc.</p>
<p>Mapping the EXE and DLL dependencies is straightforward, but accurately maintaining internal structures, such as the PEB, is a more complex task. These structures are large, mostly undocumented, and their contents can vary between Windows versions. It would be relatively simple to populate a minimalist set of fields to execute a simple &quot;Hello World&quot; application, but an improved approach should be taken to provide good compatibility.</p>
<p>Instead of manually building up a virtual environment, WinVisor launches a suspended instance of the target process and clones the entire address space into the guest. The Import Address Table (IAT) and Thread Local Storage (TLS) data directories are temporarily removed from the PE headers in memory to stop DLL dependencies from loading and to prevent TLS callbacks from executing before reaching the entry point. The process is then resumed, allowing the usual process initialization to continue (<code>LdrpInitializeProcess</code>) until it reaches the entry point of the target executable, at which point the hypervisor launches and takes control. This essentially means that Windows has done all of the hard work for us, and we now have a pre-populated user-mode address space for the target executable that is ready for execution.</p>
<p>A new thread is then created in a suspended state, with the start address pointing to the address of a custom loader function. This function populates the IAT, executes TLS callbacks, and finally executes the original entry point of the target application. This essentially simulates what the main thread would do if the process were being executed natively. The context of this thread is then &quot;cloned&quot; into the virtual CPU, and execution begins under the control of the hypervisor.</p>
<p>Memory is paged into the guest as necessary, and syscalls are intercepted, logged, and forwarded to the host OS until the virtualized target process exits.</p>
<p>As the WHP API only allows memory from the current process to be mapped into the guest, the main hypervisor logic is encapsulated within a DLL that gets injected into the target process.</p>
<h2>Virtual CPU</h2>
<p>The WHP API provides a &quot;friendly&quot; wrapper around the VMX functionality described earlier, meaning that the usual steps, such as manually populating the VMCS before executing <code>VMLAUNCH</code>,  are no longer necessary. It also exposes the functionality to user-mode, meaning a custom driver is not required. However, the virtual CPU must still be initialized appropriately via WHP prior to executing the target code. The important aspects will be described below.</p>
<h3>Control registers</h3>
<p>Only the <code>CR0</code>, <code>CR3</code>, and <code>CR4</code> control registers are relevant for this project. <code>CR0</code> and <code>CR4</code> are used to enable CPU configuration options such as protected mode, paging, and PAE. <code>CR3</code> contains the physical address of the <code>PML4</code> paging table, which will be described in further detail in the Memory Paging section.</p>
<h3>Model-specific registers</h3>
<p>Model-Specific Registers (MSRs) must also be initialized to ensure the correct operation of the virtual CPU. <code>MSR_EFER</code> contains flags for extended features, such as enabling long mode (64-bit) and <code>SYSCALL</code> instructions. <code>MSR_LSTAR</code> contains the address of the syscall handler, and <code>MSR_STAR</code> contains the segment selectors for transitioning to CPL0 (and back to CPL3) during syscalls. <code>MSR_KERNEL_GS_BASE</code> contains the shadow base address of the <code>GS</code> selector.</p>
<h3>Global descriptor table</h3>
<p>The Global Descriptor Table (GDT) defines the segment descriptors, which essentially describe memory regions and their properties for use in protected mode.</p>
<p>In long mode, the GDT has limited use and is mostly a relic of the past - x64 always operates in a flat memory mode, meaning all selectors are based at <code>0</code>. The only exceptions to this are the <code>FS</code> and <code>GS</code> registers, which are used for thread-specific purposes. Even in those cases, their base addresses are not defined by the GDT. Instead, MSRs (such as <code>MSR_KERNEL_GS_BASE</code> described above) are used to store the base address.</p>
<p>Despite this obsolescence, the GDT is still an important part of the x64 model. For example, the current privilege level is defined by the <code>CS</code> (Code Segment) selector.</p>
<h3>Task state segment</h3>
<p>In long mode, the Task State Segment (TSS) is simply used to load the stack pointer when transitioning from a lower privilege level to a higher one. As this emulator operates almost exclusively in CPL3, except for the initial bootloader and interrupt handlers, only a single page is allocated for the CPL0 stack. The TSS is stored as a special system entry within the GDT and occupies two slots.</p>
<h3>Interrupt descriptor table</h3>
<p>The Interrupt Descriptor Table (IDT) contains information about each type of interrupt, such as the handler addresses. This will be described in further detail in the Interrupt Handling section.</p>
<h3>Bootloader</h3>
<p>Most of the CPU fields mentioned above can be initialized using WHP wrapper functions, but support for certain fields (e.g. <code>XCR0</code>) only arrived in later versions of the WHP API (Windows 10 RS5). For completeness, the project includes a small “bootloader”, which runs at CPL0 upon startup and manually initializes the final parts of the CPU prior to executing the target code. Unlike a physical CPU, which would start in 16-bit real mode, the virtual CPU has already been initialized to run in long-mode (64-bit), making the boot process slightly more straightforward.</p>
<p>The following steps are performed by the bootloader:</p>
<ol>
<li>
<p>Load the GDT using the <code>LGDT</code> instruction. The source operand for this instruction specifies a 10-byte memory block which contains the base address and limit (size) of the table that was populated earlier.</p>
</li>
<li>
<p>Load the IDT using the <code>LIDT</code> instruction. The source operand for this instruction uses the same format as LGDT described above.</p>
</li>
<li>
<p>Set the TSS selector index into the task register using the <code>LTR</code> instruction. As mentioned above, the TSS descriptor exists as a special entry within the GDT (at <code>0x40</code> in this case).</p>
</li>
<li>
<p>The XCR0 register can be set using the <code>XSETBV</code> instruction. This is an additional control register which is used for optional features such as AVX. The native process executes XGETBV to get the host value, which is then copied into the guest via <code>XSETBV</code> in the bootloader.</p>
</li>
</ol>
<p>This is an important step because DLL dependencies that have already been loaded may have set global flags during their initialization process. For example, <code>ucrtbase.dll</code> checks if the CPU supports AVX via the <code>CPUID</code> instruction on startup and, if so, sets a global flag to allow the CRT to use AVX instructions for optimization reasons. If the virtual CPU attempts to execute these AVX instructions without explicitly enabling them in <code>XCR0</code> first, an undefined instruction exception will be raised.</p>
<ol start="5">
<li>
<p>Manually update <code>DS</code>, <code>ES</code>, and <code>GS</code> data segment selectors to their CPL3 equivalents (<code>0x2B</code>). Execute the <code>SWAPGS</code> instruction to load the TEB base address from <code>MSR_KERNEL_GS_BASE</code>.</p>
</li>
<li>
<p>Finally, use the <code>SYSRET</code> instruction to transition into CPL3. Prior to the <code>SYSRET</code> instruction, <code>RCX</code> is set to a placeholder address (CPL3 entry point), and <code>R11</code> is set to the initial CPL3 RFLAGS value (<code>0x202</code>). The <code>SYSRET</code> instruction automatically switches the <code>CS</code> and <code>SS</code> segment selectors to their CPL3 equivalents from <code>MSR_STAR</code>.</p>
</li>
</ol>
<p>When the <code>SYSRET</code> instruction executes, a page fault will be raised due to the invalid placeholder address in <code>RIP</code>. The emulator will catch this page fault and recognize it as a “special” address. The initial CPL3 register values will then be copied into the virtual CPU, <code>RIP</code> is updated to point to a custom user-mode loader function, and execution resumes. This function loads all DLL dependencies for the target executable, populates the IAT table, executes TLS callbacks, and then executes the original entry point. The import table and TLS callbacks are handled at this stage, rather than earlier on, to ensure their code is executed within the virtualized environment.</p>
<h2>Memory paging</h2>
<p>All memory management for the guest must be handled manually. This means a paging table must be populated and maintained, allowing the virtual CPU to translate a virtual address to a physical address.</p>
<h3>Virtual address translation</h3>
<p>For those who are not familiar with paging in x64, the paging table has four levels: <code>PML4</code>, <code>PDPT</code>, <code>PD</code>, and <code>PT</code>. For any given virtual address, the CPU walks through each layer of the table, eventually reaching the target physical address. Modern CPUs also support 5-level paging (in case the 256TB of addressable memory offered by 4-level paging isn't enough!), but this is irrelevant for the purposes of this project.</p>
<p>The following image illustrates the format of a sample virtual address:</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/winvisor-hypervisor-based-emulator/5WT-image.png" alt="Breakdown of an example virtual address" title="Breakdown of an example virtual address" /></p>
<p>Using the example above, the CPU would calculate the physical page corresponding to the virtual address <code>0x7FFB7D030D10</code> via the following table entries: <code>PML4[0xFF]</code> -&gt; <code>PDPT[0x1ED]</code> -&gt; <code>PD[0x1E8]</code> -&gt; <code>PT[0x30]</code>. Finally, the offset (<code>0xD10</code>) will be added to this physical page to calculate the exact address.</p>
<p>Bits <code>48</code> - <code>63</code> within a virtual address are unused in 4-level paging and are essentially sign-extended to match bit <code>47</code>.</p>
<p>The <code>CR3</code> control register contains the physical address of the base <code>PML4</code> table. When paging is enabled (mandatory in long-mode), all other addresses within the context of the CPU refer to virtual addresses.</p>
<h3>Page faults</h3>
<p>When the guest attempts to access memory, the virtual CPU will raise a page fault exception if the requested page isn't already present in the paging table. This will trigger a VM Exit event and pass control back to the host. When this occurs, the <code>CR2</code> control register contains the requested virtual address, although the WHP API already provides this value within the VM Exit context data. The host can then map the requested page into memory (if possible) and resume execution or throw an error if the target address is invalid.</p>
<h3>Host/guest memory mirroring</h3>
<p>As mentioned earlier, the emulator creates a child process, and all virtual memory within that process will be mapped directly into the guest using the same address layout. The Hypervisor Platform API allows us to map virtual memory from the host user-mode process directly into the physical memory of the guest. The paging table will then map virtual addresses to the corresponding physical pages.</p>
<p>Instead of mapping the entire address space of the process upfront, a fixed number of physical pages are allocated for the guest. The emulator contains a very basic memory manager, and pages are mapped &quot;on demand.&quot; When a page fault occurs, the requested page will be paged in, and execution resumes. If all page &quot;slots&quot; are full, the oldest entry is swapped out to make room for the new one.</p>
<p>In addition to using a fixed number of currently mapped pages, the emulator also uses a fixed-size page table. The size of the page table is determined by calculating the maximum possible number of tables for the amount of mapped page entries. This model results in a simple and consistent physical memory layout but comes at the cost of efficiency. In fact, the paging tables take up more space than the actual page entries.</p>
<p>There is a single PML4 table, and in the worst-case scenario, each mapped page entry will reference unique PDPT/PD/PT tables. As each table is <code>4096</code> bytes, the total page table size can be calculated using the following formula:</p>
<pre><code>PAGE_TABLE_SIZE = 4096 + (MAXIMUM_MAPPED_PAGES * 4096 * 3)
</code></pre>
<p>By default, the emulator allows for <code>256</code> pages to be mapped at any one time (<code>1024KB</code> in total). Using the formula above, we can calculate that this will require <code>3076KB</code> for the paging table, as illustrated below:</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/winvisor-hypervisor-based-emulator/8gv-image.png" alt="Diagram illustrating the physical memory map within the virtualized guest" title="Diagram illustrating the physical memory map within the virtualized guest" /></p>
<p>In practice, many of the page table entries will be shared, and a lot of the space allocated for the paging tables will remain unused. However, as this emulator functions well even with a small number of pages, this level of overhead is not a major concern.</p>
<p>The CPU maintains a hardware-level cache for the paging table known as the Translation Lookaside Buffer (TLB). When translating a virtual address to a physical address, the CPU will first check the TLB. If a matching entry is not found in the cache (known as a “TLB miss”), the paging tables will be read instead. For this reason, it is important to flush the TLB cache whenever the paging tables have been rebuilt to prevent it from falling out of sync. The simplest way to flush the entire TLB is to reset the <code>CR3</code> register value.</p>
<h2>Syscall handling</h2>
<p>As the target program executes, any system calls that occur within the guest must be handled by the host. This emulator handles both <code>SYSCALL</code> instructions and legacy (interrupt-based) syscalls. <code>SYSENTER</code> is not used in long-mode and, therefore, is not supported by WinVisor.</p>
<h3>Fast syscall (SYSCALL)</h3>
<p>When a <code>SYSCALL</code> instruction executes, the CPU transitions to CPL0 and loads <code>RIP</code> from <code>MSR_LSTAR</code>. In the Windows kernel, this would point to <code>KiSystemCall64</code>. <code>SYSCALL</code> instructions won't inherently trigger a VM Exit event, but the emulator sets <code>MSR_LSTAR</code> to a reserved placeholder address — <code>0xFFFF800000000000</code> in this case. When a <code>SYSCALL</code> instruction is executed, a page fault will be raised when RIP is set to this address, and the call can be intercepted. This placeholder is a kernel address in Windows and won't cause any conflicts with the user-mode address space.</p>
<p>Unlike legacy syscalls, the <code>SYSCALL</code> instruction doesn't swap the <code>RSP</code> value during the transition to CPL0, so the user-mode stack pointer can be retrieved directly from <code>RSP</code>.</p>
<h3>Legacy syscalls (INT 2E)</h3>
<p>Legacy interrupt-based syscalls are slower and have more overhead than the <code>SYSCALL</code> instruction, but despite this, they are still supported by Windows. As the emulator already contains a framework for handling interrupts, adding support for legacy syscalls is very simple. When a legacy syscall interrupt is caught, it can be forwarded to the “common” syscall handler after some minor translations — specifically, retrieving the stored user-mode <code>RSP</code> value from the CPL0 stack.</p>
<h3>Syscall forwarding</h3>
<p>After the emulator creates the &quot;main thread&quot; whose context gets cloned into the virtual CPU, this native thread is reused as a proxy to forward syscalls to the host. Reusing the same thread maintains consistency for the TEB and any kernel state between the guest and the host. Win32k, in particular, relies on many thread-specific states, which should be reflected in the emulator.</p>
<p>When a syscall occurs, either by a <code>SYSCALL</code> instruction or a legacy interrupt, the emulator intercepts it and transfers it to a universal handler function. The syscall number is stored in the <code>RAX</code> register, and the first four parameter values are stored in <code>R10</code>, <code>RDX</code>, <code>R8</code>, and <code>R9</code>, respectively. <code>R10</code> is used for the first parameter instead of the usual <code>RCX</code> register because the <code>SYSCALL</code> instruction overwrites <code>RCX</code> with the return address. The legacy syscall handler in Windows (<code>KiSystemService</code>) also uses <code>R10</code> for compatibility, so it doesn’t need to be handled differently in the emulator. The remaining parameters are retrieved from the stack.</p>
<p>We don’t know the exact number of parameters expected for any given syscall number, but luckily, this doesn’t matter. We can simply use a fixed amount, and as long as the number of supplied parameters is greater than or equal to the actual number, the syscall will function correctly. A simple assembly stub will be dynamically created, populating all of the parameters, executing the target syscall, and returning cleanly.</p>
<p>Testing showed that the maximum number of parameters currently used by Windows syscalls is <code>17</code> (<code>NtAccessCheckByTypeResultListAndAuditAlarmByHandle</code>, <code>NtCreateTokenEx</code>, and <code>NtUserCreateWindowEx</code>). WinVisor uses <code>32</code> as the maximum number of parameters to allow for potential future expansion.</p>
<p>After executing the syscall on the host, the return value is copied to <code>RAX</code> in the guest. <code>RIP</code> is then transferred to a <code>SYSRET</code> instruction (or <code>IRETQ</code> for legacy syscalls) before resuming the virtual CPU for a seamless transition back to user-mode.</p>
<h3>Syscall logging</h3>
<p>By default, the emulator simply forwards guest syscalls to the host and logs them to the console. However, some additional steps are necessary to convert the raw syscalls into a readable format.</p>
<p>The first step is to convert the syscall number to a name. Syscall numbers are made up of multiple parts: bits <code>12</code> - <code>13</code> contain the system service table index (<code>0</code> for <code>ntoskrnl</code>, <code>1</code> for <code>win32k</code>), and bits <code>0</code> - <code>11</code> contain the syscall index within the table. This information allows us to perform a reverse-lookup within the corresponding user-mode module (<code>ntdll</code> / <code>win32u</code>) to resolve the original syscall name.</p>
<p>The next step is to determine the number of parameter values to display for each syscall. As mentioned above, the emulator passes <code>32</code> parameter values to each syscall, even if most of them are not used. However, logging all <code>32</code> values for each syscall wouldn't be ideal for readability reasons. For example, a simple <code>NtClose(0x100)</code> call would be printed as <code>NtClose(0x100, xxx, xxx, xxx, xxx, xxx, xxx, xxx, xxx, ...)</code>. As mentioned earlier, there is no simple way to automatically determine the exact number of parameters for each syscall, but there is a trick that we can use to estimate it with high accuracy.</p>
<p>This trick relies on the 32-bit system libraries used by WoW64. These libraries use the stdcall calling convention, which means the caller pushes all parameters onto the stack, and they are cleaned internally by the callee before returning. In contrast, native x64 code places the first 4 parameters into registers, and the caller is responsible for managing the stack.</p>
<p>For example, the <code>NtClose</code> function in the WoW64 version of <code>ntdll.dll</code> ends with the <code>RET 4</code> instruction. This pops an additional 4-bytes off the stack after the return address, which implies that the function takes one parameter. If the function used <code>RET 8</code>, this would suggest that it takes 2 parameters, and so on.</p>
<p>Even though the emulator runs as a 64-bit process, we can still load the 32-bit copies of <code>ntdll.dll</code> and <code>win32u.dll</code> into memory - either manually or mapped using <code>SEC_IMAGE</code>. A custom version of <code>GetProcAddress</code> must be written to resolve the WoW64 export addresses, but this is a trivial task. From here, we can automatically find the corresponding WoW64 export for each syscall, scan for the <code>RET</code> instruction to calculate the number of parameters, and store the value in a lookup table.</p>
<p>This method is not perfect, and there are a number of ways that this could fail:</p>
<ul>
<li>A small number of native syscalls don't exist in WoW64, such as <code>NtUserSetWindowLongPtr</code>.</li>
<li>If a 32-bit function contains a 64-bit parameter, it will be split into 2x 32-bit parameters internally, whereas the corresponding 64-bit function would only require a single parameter for the same value.</li>
<li>The WoW64 syscall stub functions within Windows could change in such a way that causes the existing <code>RET</code> instruction search to fail.</li>
</ul>
<p>Despite these pitfalls, the results will be accurate for the vast majority of syscalls without having to rely on hardcoded values. In addition, these values are only used for logging purposes and won't affect anything else, so minor inaccuracies are acceptable in this context. If a failure is detected, it will revert back to displaying the maximum number of parameter values.</p>
<h3>Syscall hooking</h3>
<p>If this project were being used for sandboxing purposes, blindly forwarding all syscalls to the host would be undesirable for obvious reasons. The emulator contains a framework that allows specific syscalls to be easily hooked if necessary.</p>
<p>By default, only <code>NtTerminateThread</code> and <code>NtTerminateProcess</code> are hooked to catch the guest process exiting.</p>
<h2>Interrupt handling</h2>
<p>Interrupts are defined by the IDT, which is populated before the virtual CPU execution begins. When an interrupt occurs, the current CPU state is pushed onto the CPL0 stack (<code>SS</code>, <code>RSP</code>, <code>RFLAGS</code>, <code>CS</code>, <code>RIP</code>), and <code>RIP</code> is set to the target handler function.</p>
<p>As with <code>MSR_LSTAR</code> for the SYSCALL handler, the emulator populates all interrupt handler addresses with placeholder values (<code>0xFFFFA00000000000</code> - <code>0xFFFFA000000000FF</code>). When an interrupt occurs, a page fault will occur within this range, which we can catch. The interrupt index can be extracted from the lowest 8-bits of the target address (e.g., <code>0xFFFFA00000000003</code> is <code>INT 3</code>), and the host can handle it as necessary.</p>
<p>At present, the emulator only handles <code>INT 1</code> (single-step), <code>INT 3</code> (breakpoint), and <code>INT 2E</code> (legacy syscall). If any other interrupt is caught, the emulator will exit with an error.</p>
<p>When an interrupt has been handled, <code>RIP</code> is transferred to an <code>IRETQ</code> instruction, which returns to user-mode cleanly. Some types of interrupts push an additional &quot;error code&quot; value onto the stack - if this is the case, it must be popped prior to the <code>IRETQ</code> instruction to avoid stack corruption. The interrupt handler framework within this emulator contains an optional flag to handle this transparently.</p>
<h2>Hypervisor shared page bug</h2>
<p>Windows 10 introduced a new type of shared page which is located close to <code>KUSER_SHARED_DATA</code>. This page is used by timing-related functions such as <code>RtlQueryPerformanceCounter</code> and <code>RtlGetMultiTimePrecise</code>.</p>
<p>The exact address of this page can be retrieved with <code>NtQuerySystemInformation</code>, using the <code>SystemHypervisorSharedPageInformation</code> information class. The <code>LdrpInitializeProcess</code> function stores the address of this page in a global variable (<code>RtlpHypervisorSharedUserVa</code>) during process startup.</p>
<p>The WHP API seems to contain a bug that causes the <code>WHvRunVirtualProcessor</code> function to get stuck in an infinite loop if this shared page is mapped into the guest and the virtual CPU attempts to read from it.</p>
<p>Time constraints limited the ability to fully investigate this; however, a simple workaround was implemented. The emulator patches the <code>NtQuerySystemInformation</code> function within the target process and forces it to return <code>STATUS_INVALID_INFO_CLASS</code> for <code>SystemHypervisorSharedPageInformation</code> requests. This causes the <code>ntdll</code> code to fall back to traditional methods.</p>
<h2>Demos</h2>
<p>Some examples of common Windows executables being emulated under this virtualized environment below:</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/winvisor-hypervisor-based-emulator/Slj_Image_3.png" alt="ping.exe being emulated by WinVisor" title="ping.exe being emulated by WinVisor" /></p>
<p><img src="https://www.elastic.co/security-labs/assets/images/winvisor-hypervisor-based-emulator/gs2_Image_4.png" alt="cmd.exe being emulated by WinVisor" title="cmd.exe being emulated by WinVisor" /></p>
<p><img src="https://www.elastic.co/security-labs/assets/images/winvisor-hypervisor-based-emulator/zkL_Image_5.png" alt="notepad.exe being emulated by WinVisor, including a hooked syscall (NtUserCreateWindowEx) for demonstration purposes" title="notepad.exe being emulated by WinVisor, including a hooked syscall (NtUserCreateWindowEx) for demonstration purposes" /></p>
<h2>Limitations</h2>
<p>The emulator has several limitations that make it unsafe to use as a secure sandbox in its current form.</p>
<h3>Safety issues</h3>
<p>There are several ways to &quot;escape&quot; the VM, such as simply creating a new process/thread, scheduling asynchronous procedure calls (APCs), etc.</p>
<p>Windows GUI-related syscalls can also make nested calls directly back into user-mode from the kernel, which would currently bypass the hypervisor layer. For this reason, GUI executables such as notepad.exe are only partially virtualized when run under WinVisor.</p>
<p>To demonstrate this, WinVisor includes an <code>-nx</code> command-line switch to the emulator. This forces the entire target EXE image to be marked as non-executable in memory prior to starting the virtual CPU, causing the process to crash if the host process attempts to execute any of the code natively. However, this is still unsafe to rely on — the target application could make the region executable again or simply allocate executable memory elsewhere.</p>
<p>As the WinVisor DLL is injected into the target process, it exists within the same virtual address space as the target executable. This means the code running under the virtual CPU is able to directly access the memory within the host hypervisor module, which could potentially corrupt it.</p>
<h3>Non-executable guest memory</h3>
<p>While the virtual CPU is set up to support NX, all memory regions are currently mirrored into the guest with full RWX access.</p>
<h3>Single-thread only</h3>
<p>The emulator currently only supports virtualizing a single thread. If the target executable creates additional threads, they will be executed natively. To support multiple threads, a pseudo-scheduler could be developed to handle this in the future.</p>
<p>The Windows parallel loader is disabled to ensure all module dependencies are loaded by a single thread.</p>
<h3>Software exceptions</h3>
<p>Virtualized software exceptions are not currently supported. If an exception occurs, the system will call the <code>KiUserExceptionDispatcher</code> function natively as usual.</p>
<h2>Conclusion</h2>
<p>As seen above, the emulator performs well with a wide range of executables in its current form. While it is currently effective for logging syscalls and interrupts, a lot of further work would be required to make it safe to use for malware analysis purposes. Despite this, the project provides an effective framework for future development.</p>
<h2>Project links</h2>
<p><a href="https://github.com/x86matthew/WinVisor">https://github.com/x86matthew/WinVisor</a></p>
<p>The author can be found on X at <a href="https://x.com/x86matthew">@x86matthew</a>.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/security-labs/assets/images/winvisor-hypervisor-based-emulator/winvisor.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[STIXy Situations: ECSaping your threat data]]></title>
            <link>https://www.elastic.co/security-labs/stixy-situations-ecsaping-your-threat-data</link>
            <guid>stixy-situations-ecsaping-your-threat-data</guid>
            <pubDate>Fri, 09 Feb 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Structured threat data is commonly formatted using STIX. To help get this data into Elasticsearch, we’re releasing a Python script that converts STIX to an ECS format to be ingested into your stack.]]></description>
            <content:encoded><![CDATA[<h2>Preamble</h2>
<p>Organizations that use threat indicators or observables consume, create, and/or (ideally) publish threat data. This data can be used internally or externally as information or intelligence to inform decision-making and event prioritization.</p>
<p>While there are several formats for this information to be structured into, the de facto industry standard is <a href="https://oasis-open.github.io/cti-documentation/stix/intro">Structured Threat Information Expression (STIX)</a>. STIX is managed by the <a href="https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=cti">OASIS Cyber Threat Intelligence Technical Committee</a> and enables organizations to share threat data in a standard and machine-readable format.</p>
<p>At Elastic, we developed the <a href="https://www.elastic.co/guide/en/ecs/current/ecs-reference.html">Elastic Common Schema (ECS)</a> as a data normalization capability. “[ECS] is an open source specification, developed with support from the Elastic user community. ECS defines a common set of fields for storing event data in Elasticsearch, such as logs and metrics.” In April of 2023, <a href="https://www.elastic.co/blog/ecs-elastic-common-schema-otel-opentelemetry-announcement">Elastic contributed ECS</a> to the <a href="https://opentelemetry.io/docs/concepts/semantic-conventions/">OpenTelemetry Semantic Conventions (OTel)</a> as a commitment to the joint development of an open schema.</p>
<p>The security community shares threat data in the STIX format, so to store that data in Elasticsearch for analysis and threat detection [<a href="https://www.elastic.co/guide/en/security/current/threat-intel-hash-indicator-match.html">1</a>] [<a href="https://www.elastic.co/guide/en/security/current/threat-intel-ip-address-indicator-match.html">2</a>] [<a href="https://www.elastic.co/guide/en/security/current/threat-intel-url-indicator-match.html">3</a>] [<a href="https://www.elastic.co/guide/en/security/current/threat-intel-windows-registry-indicator-match.html">4</a>], we created a tool that converts STIX documents into ECS and outputs the threat data either as a file or directly into Elasticsearch indices. If this was a challenge for us, it was a challenge for others - therefore, we decided to release a version of the tool.</p>
<p>This tool uses the <a href="https://www.elastic.co/licensing/elastic-license">Elastic License 2.0</a> and is available for download <a href="https://github.com/elastic/labs-releases/tree/main/tools/stix-to-ecs">here</a>.</p>
<h2>Getting started</h2>
<p>This project will take a STIX 2.x formatted JSON document and create an ECS version. There are three output options: STDOUT as JSON, an NDJSON file, and/or directly to an Elasticsearch cluster.</p>
<h3>Prerequisites</h3>
<p>The STIX 2 ECS project requires Python 3.10+ and the <a href="https://pypi.org/project/stix2/">stix2</a>, <a href="https://pypi.org/project/elasticsearch/">Elasticsearch</a>, and <a href="https://pypi.org/project/getpass4/">getpass</a> modules.</p>
<p>If exporting to Elasticsearch, you will need the host information and authentication credentials. API authentication is not yet implemented.</p>
<h3>Setup</h3>
<p>Create a virtual environment and install the required prerequisites.</p>
<pre><code>git clone https://github.com/elastic/labs-releases.git
cd tools/stix2ecs
python -m venv /path/to/virtual/environments/stix2ecs
source /path/to/virtual/environments/stix2ecs/bin/activate
python -m pip install -r requirements.txt
</code></pre>
<h2>Operation</h2>
<p>The input is a STIX 2.x JSON document (or a folder of JSON documents); the output defaults to STDOUT, with an option to create an NDJSON file and/or send to an Elasticsearch cluster.</p>
<pre><code>stix_to_ecs.py [-h] -i INPUT [-o OUTPUT] [-e] [--index INDEX] [--url URL] \
[--user USER] [-p PROVIDER] [-r]
</code></pre>
<p>By default, the ECS file is named the same as the STIX file input but with <code>.ecs.ndjson</code> appended.</p>
<h3>Arguments</h3>
<p>The script has several arguments, the only mandatory field is <code>-i</code> for the input. By default, the script will output the NDJSON document to STDOUT.</p>
<table>
<thead>
<tr>
<th>Option</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>-h</td>
<td>displays the help menu</td>
</tr>
<tr>
<td>-i</td>
<td>specifies the input STIX document (mandatory)</td>
</tr>
<tr>
<td>-o</td>
<td>specifies the output ECS document (optional)</td>
</tr>
<tr>
<td>-p</td>
<td>defines the ECS provider field (optional)</td>
</tr>
<tr>
<td>-r</td>
<td>recursive mode to convert multiple STIX documents (optional)</td>
</tr>
<tr>
<td>-e</td>
<td>specifies the Elasticsearch output mode (optional)</td>
</tr>
<tr>
<td>--index</td>
<td>defines the Elasticsearch Index, requires <code>-e</code> (optional)</td>
</tr>
<tr>
<td>--url</td>
<td>defines the Elasticsearch URL, requires <code>-e</code> (optional)</td>
</tr>
<tr>
<td>--user</td>
<td>defines the Elasticsearch username, requires <code>-e</code> (optional)</td>
</tr>
</tbody>
</table>
<h2>Examples</h2>
<p>There are two sample files located in the <code>test-inputs/</code> directory. One is from <a href="https://www.cisa.gov/topics/cyber-threats-and-advisories/information-sharing/automated-indicator-sharing-ais">CISA</a> (Cybersecurity &amp; Infrastructure Security Agency), and one is from <a href="https://github.com/OpenCTI-Platform/opencti">OpenCTI</a> (an open source threat intelligence platform).</p>
<h3>STIX file input to STDOUT</h3>
<p>This will output the STIX document to STDOUT in ECS format.</p>
<pre><code>python stix_to_ecs.py -i test-inputs/cisa_sample_stix.json | jq

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

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

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

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

{
  &quot;took&quot; : 2,
  &quot;timed_out&quot; : false,
  &quot;_shards&quot; : {
    &quot;total&quot; : 1,
    &quot;successful&quot; : 1,
    &quot;skipped&quot; : 0,
    &quot;failed&quot; : 0
  },
  &quot;hits&quot; : {
    &quot;total&quot; : {
      &quot;value&quot; : 3,
      &quot;relation&quot; : &quot;eq&quot;
    },
    &quot;max_score&quot; : 1.0,
    &quot;hits&quot; : [
      {
        &quot;_index&quot; : &quot;stix2ecs&quot;,
        &quot;_id&quot; : &quot;n2lt8IwBahlUtp0hzm9i&quot;,
        &quot;_score&quot; : 1.0,
        &quot;_source&quot; : {
          &quot;threat&quot; : {
            &quot;indicator&quot; : {
              &quot;file&quot; : {
                &quot;name&quot; : &quot;123.ps1&quot;,
                &quot;hash&quot; : {
                  &quot;sha256&quot; : &quot;ED5D694D561C97B4D70EFE934936286FE562ADDF7D6836F795B336D9791A5C44&quot;
                }
              },
              &quot;type&quot; : &quot;file&quot;,
              &quot;description&quot; : &quot;Simple indicator of observable {ED5D694D561C97B4D70EFE934936286FE562ADDF7D6836F795B336D9791A5C44}&quot;,
              &quot;first_seen&quot; : &quot;2023-11-21T18:57:25.000Z&quot;,
              &quot;provider&quot; : &quot;identity--b3bca3c2-1f3d-4b54-b44f-dac42c3a8f01&quot;,
              &quot;modified_at&quot; : &quot;2023-11-21T18:57:25.000Z&quot;,
              &quot;marking&quot; : {
                &quot;tlp&quot; : &quot;clear&quot;
              }
            }
          }
        }
      }
...
</code></pre>
<p>If you’re using Kibana, you can <a href="https://www.elastic.co/guide/en/kibana/current/data-views.html">create a Data View</a> for your <code>stix2ecs</code> index to view the ingested indicators.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/stixy-situations-ecsaping-your-threat-data/image1.png" alt="STIX2ECS data in Kibana" title="STIX2ECS data in Kibana" /></p>
<p>Finally, you can use this as an indicator source for <a href="https://www.elastic.co/guide/en/security/current/prebuilt-rule-1-0-2-threat-intel-indicator-match.html">Indicator Match rules</a>.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/stixy-situations-ecsaping-your-threat-data/image2.png" alt="Indicator Match rule created with STIX2ECS data" title="Indicator Match rule created with STIX2ECS data" /></p>
<h2>Summary</h2>
<p>We hope this project helps your organization analyze and operationalize your threat data. If you’re new to the Elastic Common Schema, you can learn more about that <a href="https://www.elastic.co/guide/en/ecs/current/index.html">here</a>.</p>
<p>As always, please feel free to open an <a href="https://github.com/elastic/labs-releases/issues">issue</a> with any questions, comments, concerns, or complaints.</p>
<h2>About Elastic Security Labs</h2>
<p>Elastic Security Labs is the threat intelligence branch of Elastic Security dedicated to creating positive change in the threat landscape. Elastic Security Labs provides publicly available research on emerging threats with an analysis of strategic, operational, and tactical adversary objectives, then integrates that research with the built-in detection and response capabilities of Elastic Security.</p>
<p>Follow Elastic Security Labs on Twitter <a href="https://twitter.com/elasticseclabs?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor">@elasticseclabs</a> and check out our research at <a href="https://www.elastic.co/security-labs/">www.elastic.co/security-labs/</a>.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/security-labs/assets/images/stixy-situations-ecsaping-your-threat-data/photo-edited-07@2x.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Dancing the night away with named pipes - PIPEDANCE client release]]></title>
            <link>https://www.elastic.co/security-labs/dancing-the-night-away-with-named-pipes</link>
            <guid>dancing-the-night-away-with-named-pipes</guid>
            <pubDate>Thu, 05 Oct 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[In this publication, we will walk through this client application’s functionality and how to get started with the tool.]]></description>
            <content:encoded><![CDATA[<h2>Introduction</h2>
<p>This year at <a href="https://www.virusbulletin.com/conference/">VB2023</a>, a globally renowned malware conference, Daniel Stepanic of the Elastic Security Labs team presented new insights into PIPEDANCE  – a malware we <a href="https://twitter.com/elasticseclabs/status/1630289166008287232">disclosed</a> earlier this year. In addition to the talk, we released a <a href="https://github.com/elastic/PIPEDANCE">client</a> application that enables threat research, offering learning opportunities for both offensive and defensive teams. In this publication, we will walk through this client application’s functionality and how to get started with the tool. Our goal with this research is to help defenders improve their understanding of PIPEDANCE by emulating techniques from this malware, used by a formidable threat group. This includes different behaviors such as:</p>
<ul>
<li>Command and control communication through named pipes</li>
<li>Different styles of process injection</li>
<li>Performing network connectivity checks</li>
<li>System/network discovery and enumeration</li>
</ul>
<h2>Recap</h2>
<p>PIPEDANCE is a custom malware family used by a state-sponsored group to perform post-compromise activities. It's purpose-built to enable lateral movement, deploy additional implants, and perform reconnaissance functions. PIPEDANCE uses named pipes as its main channel for command and control communication. With a variety of unique features, we believe it’s a useful example to share for research purposes and can help defenders validate security tooling.</p>
<p>For a detailed analysis of the PIPEDANCE malware, check out our <a href="https://www.elastic.co/security-labs/twice-around-the-dance-floor-with-pipedance">previous research</a>.</p>
<h2>Development</h2>
<p>To get a better understanding of different features within malware, our team at Elastic Security Labs sometimes writes custom applications and controllers to interact with the malware or malware infrastructure. This process helps cultivate knowledge of a sample’s core features, assists in understanding the control flow better, and further validates different areas such as inputs and outputs to functions and data structures. Another key benefit is to uncover functionality that was not directly observed during an intrusion but is still contained in the malware. This allows our team to collect more intelligence, build additional detections, and understand more of the adversary’s objectives behind the malware.</p>
<p>While we don't cover these exact scenarios in this publication, here are some things that you can do with the client (but you may think of others):</p>
<ul>
<li>Understand how malware abuses named pipes</li>
<li>Verify data sources for security tooling around network activity using named pipes</li>
<li>Build a network decoder using PCAP data from PIPEDANCE’s communication requests</li>
</ul>
<p>With the release of the client, we're hoping that the community can write additional PIPEDANCE clients in your favorite language and compare notes.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/dancing-the-night-away-with-named-pipes/image3.jpg" alt="Emulated PIPEDANCE Injection functionality" /></p>
<h2>Getting Started</h2>
<p><em><strong>Note:</strong> Please review the <a href="https://github.com/elastic/PIPEDANCE/blob/main/README.md#requirements">requirements</a> before setting up the lab environment. For this example, we will use two different endpoints in the same local network where named pipes, inter-process communication, and SMB settings are configured properly.</em></p>
<p>The first step is to download the PIPEDANCE <a href="https://malshare.com/sample.php?action=detail&amp;hash=e5ae20ac5bc2f02a136c3cc3c0b457476d39f809f28a1c578cda994a83213887">sample</a> (free <a href="https://malshare.com/register.php">registration</a> required) and start the program without any arguments on one endpoint. This machine is the targeted endpoint where the adversary is interested in running additional implants and performing reconnaissance. After execution, a named pipe will be created and await an incoming connection from our client.</p>
<pre><code>.\e5ae20ac5bc2f02a136c3cc3c0b457476d39f809f28a1c578cda994a83213887
</code></pre>
<p>Now that PIPEDANCE is running on our targeted machine, download and compile the client files within the <a href="https://github.com/elastic/PIPEDANCE">repository</a>. The PIPEDANCE malware uses a hard-coded string, <code>u0hxc1q44vhhbj5oo4ohjieo8uh7ufxe</code>, that serves as the named pipe name and RC4 key.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/dancing-the-night-away-with-named-pipes/image2.png" alt="Hardcoded named pipe/RC4 key within PIPEDANCE" /></p>
<p>Take the newly compiled client program and execute it on a separate endpoint with one argument using either the target IP address or hostname of the machine running PIPEDANCE (machine from the previous step). An example of this would be:</p>
<pre><code>pipedance_client.exe 192.168.47.130
</code></pre>
<p>After execution, the client will check in with the PIPEDANCE victim to retrieve the PID of the malicious process, working directory, and user running the process. A menu of commands should be listed allowing the operator to perform various post-compromise activities.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/dancing-the-night-away-with-named-pipes/image1.png" alt="PIPEDANCE Client Menu" /></p>
<p>The appendix below contains the functions and their supported arguments.</p>
<h2>Conclusion</h2>
<p>As part of our research investigating PIPEDANCE, we are releasing a client application that interacts with the malware. This tool can be used to evaluate existing security prevention/detection technologies as well as used for threat research purposes. Please check out our <a href="https://github.com/elastic/PIPEDANCE">repository</a>, there is also a detection section with behavioral/YARA/hunting rules.</p>
<h2>Appendix</h2>
<h3>Handler Commands</h3>
<table>
<thead>
<tr>
<th>Command ID</th>
<th>Description</th>
<th>Arguments</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>Stop</td>
<td>PIPEDANCE client</td>
</tr>
<tr>
<td>1</td>
<td>Terminate process by PID</td>
<td>PID (ex. 9867)</td>
</tr>
<tr>
<td>2</td>
<td>Run shell command and print output</td>
<td>Command (ex. ipconfig)</td>
</tr>
<tr>
<td>4</td>
<td>List files in current working directory</td>
<td></td>
</tr>
<tr>
<td>6</td>
<td>Write file to disk</td>
<td>Filename (full path), file content</td>
</tr>
<tr>
<td>7</td>
<td>Get current working directory</td>
<td></td>
</tr>
<tr>
<td>8</td>
<td>Change current working directory</td>
<td>Folder path</td>
</tr>
<tr>
<td>9</td>
<td>List running processes</td>
<td></td>
</tr>
<tr>
<td>23</td>
<td>Create random process with hijacked token from provided PID and inject shellcode (32bits)</td>
<td>PID (token hijack), shellcode</td>
</tr>
<tr>
<td>24</td>
<td>Create random process with hijacked token from provided PID and inject shellcode (64bits)</td>
<td>PID (token hijack), shellcode</td>
</tr>
<tr>
<td>25</td>
<td>Open process from provided PID and inject shellcode (32bits)</td>
<td>PID (thread hijack), shellcode</td>
</tr>
<tr>
<td>26</td>
<td>Open process from provided PID and inject shellcode (64bits)</td>
<td>PID (thread hijack), shellcode</td>
</tr>
<tr>
<td>71</td>
<td>HTTP connectivity check</td>
<td>Domain (ex. google.com)</td>
</tr>
<tr>
<td>72</td>
<td>DNS connectivity check with provided DNS server IP</td>
<td>DNS server IP</td>
</tr>
<tr>
<td>73</td>
<td>ICMP connectivity check</td>
<td>ICMP server IP</td>
</tr>
<tr>
<td>74</td>
<td>TCP connectivity check</td>
<td>IP, port</td>
</tr>
<tr>
<td>75</td>
<td>DNS connectivity check without DNS server</td>
<td></td>
</tr>
<tr>
<td>99</td>
<td>Disconnect pipe / exit thread</td>
<td></td>
</tr>
<tr>
<td>100</td>
<td>Terminate PIPEDANCE process / disconnect Pipe / exit thread</td>
<td></td>
</tr>
</tbody>
</table>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/security-labs/assets/images/dancing-the-night-away-with-named-pipes/photo-edited-12@2x.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Click, Click… Boom! Automating Protections Testing with Detonate]]></title>
            <link>https://www.elastic.co/security-labs/click-click-boom-automating-protections-testing-with-detonate</link>
            <guid>click-click-boom-automating-protections-testing-with-detonate</guid>
            <pubDate>Thu, 04 May 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[To automate this process and test our protections at scale, we built Detonate, a system that is used by security research engineers to measure the efficacy of our Elastic Security solution in an automated fashion.]]></description>
            <content:encoded><![CDATA[<h2>Preamble</h2>
<p>Imagine you are an Endpoint artifact developer. After you put in the work to ensure protection against conventional shellcode injections or ransomware innovations, how do you know it actually works before you send it out into the world?</p>
<p>First, you set up your end-to-end system, which involves setting up several services, the infrastructure, network configuration, and more. Then, you run some malware; the data you collect answers questions about performance and efficacy, and may be an important research resource in the future. After you spend a day testing and gathering your results, you may want to run several hundred hashes over multiple kinds of operating systems and machine types, a daunting task if done entirely manually.</p>
<p>To automate this process and test our protections at scale, we built Detonate, a system that is used by security research engineers to measure the efficacy of our Elastic Security solution in an automated fashion. Our goal is to have it take security researchers only a couple of clicks to test our protections against malware. (Thus: click, click… boom!)</p>
<p>In this series of posts, we’ll: - Introduce Detonate and why we built it - Explore how Detonate works and the technical implementation details - Describe case studies on how our teams use it at Elastic - Discuss opening our efficacy testing to the community to help the world protect their data from attack</p>
<p>Interested in other posts on Detonate? Check out <a href="https://www.elastic.co/security-labs/into-the-weeds-how-we-run-detonate">Part 2 - Into The Weeds: How We Run Detonate</a> where we break down how Detonate works and dive deeper into the technical implementation.</p>
<h2>What is Detonate?</h2>
<p>At a high level, Detonate runs malware and other potentially malicious software in a controlled (i.e., sandboxed) environment where the full suite of Elastic Security capabilities are enabled. Detonate accepts a file hash (usually a SHA256) and performs the following actions:</p>
<ul>
<li>Prepares all files needed for detonation, including the malicious file</li>
<li>Provisions a virtual machine (VM) instance in a sandboxed environment, with limited connectivity to the outside world</li>
<li>Waits until file execution completes; this happens when, for example, an execution result file is found or the VM instance is stopped or older than a task timeout</li>
<li>Stops the running VM instance (if necessary) and cleans up the sandboxed environment</li>
<li>Generates an event summary based on telemetry and alerts produced during detonation</li>
</ul>
<p>The results of these detonations are made available to the team for research and development purposes. By post-processing the logs, events, and alerts collected during detonation, we can enrich them with third-party intelligence and other sources to evaluate the efficacy of new and existing Elastic Security protection features.</p>
<h2>What does it help us with?</h2>
<h3>Measuring Efficacy</h3>
<p>To build the best EPP on the market, we have to continuously measure the effectiveness of our product against the latest threats. Detonate is used to execute many tens of thousands of samples every month from our data feeds. Gaps in coverage are automatically identified and used to prioritize improvements to our protections.</p>
<h3>Supporting existing protections</h3>
<p>Many of our protections have associated artifacts (such as machine learning models and rule definitions) which receive regular updates. These updates need testing to ensure we identify and remediate regressions before they end up in a user’s environment.</p>
<p>Detonate provides a framework and suite of tools to automate the analysis involved in this testing process. By leveraging a corpus of hashes with known good and bad software, we can validate our protections before they are deployed to users.</p>
<h3>Threat research</h3>
<p>Some of our security researchers scour the internet daily for new and emerging threats. By giving them an easy-to-use platform to test malicious software they find in the wild, we better understand how Elastic Security defends against those threats or if we need to update our protections.</p>
<h3>Evaluating new protections</h3>
<p>In addition to testing existing protections, new protections run the risk of adverse interactions with our existing suite of layered capabilities. A new protection may be easily tested on its own, but tests may hide unintended interactions or conflicts with existing protections. Detonate provides a way for us to customize the configuration of the Elastic Stack and individual protections to more easily find and identify such conflicts earlier in development.</p>
<h2>What’s next?</h2>
<p>In this publication, we introduced Detonate &amp; what we use it for at Elastic. We discussed the benefits it provides our team when assessing the performance of our security artifacts.</p>
<p>Now that you know what it is, we will break down how Detonate works. In our next post, we’ll dive deeper into the technical implementation of Detonate and how we’re able to create this sandboxed environment in practice.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/security-labs/assets/images/click-click-boom-automating-protections-testing-with-detonate/blog-thumb-tools-various.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Unpacking ICEDID]]></title>
            <link>https://www.elastic.co/security-labs/unpacking-icedid</link>
            <guid>unpacking-icedid</guid>
            <pubDate>Thu, 04 May 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[ICEDID is known to pack its payloads using custom file formats and a custom encryption scheme. We are releasing a set of tools to automate the unpacking process and help analysts and the community respond to ICEDID.]]></description>
            <content:encoded><![CDATA[<h2>Preamble</h2>
<p>ICEDID is a malware family <a href="https://securityintelligence.com/new-banking-trojan-icedid-discovered-by-ibm-x-force-research/">discovered</a>in 2017 by IBM X-force researchers and is associated with the theft of login credentials, banking information, and other personal information. ICEDID has always been a prevalent family but achieved even more growth since EMOTET’s temporary <a href="https://www.justice.gov/opa/pr/emotet-botnet-disrupted-international-cyber-operation">disruption</a> in early 2021. ICEDID has been linked to the distribution of several distinct malware families including <a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.darkvnc">DarkVNC</a> and <a href="https://www.cybereason.com/blog/threat-analysis-report-all-paths-lead-to-cobalt-strike-icedid-emotet-and-qbot">COBALT STRIKE</a>. Regular industry reporting, including research publications like this one, help mitigate this threat.</p>
<p>ICEDID is known to pack its payloads using custom file formats and a custom encryption scheme. Following our latest <a href="https://www.elastic.co/security-labs/thawing-the-permafrost-of-icedid-summary">ICEDID research</a> that covers the GZip variant execution chain.</p>
<p>In this tutorial, we will introduce these tools by unpacking a recent ICEDID sample starting with downloading a copy of the fake GZip binary:</p>
<p><strong>Analyzing malware can be dangerous to systems and should only be attempted by experienced professionals in a controlled environment, like an isolated virtual machine or analysis sandbox. Malware can be designed to evade detection and infect other systems, so it's important to take all necessary precautions and use specialized tools to protect yourself and your systems.</strong></p>
<p><a href="https://bazaar.abuse.ch/sample/54d064799115f302a66220b3d0920c1158608a5ba76277666c4ac532b53e855f/"><strong>54d064799115f302a66220b3d0920c1158608a5ba76277666c4ac532b53e855f</strong></a></p>
<h2>Environment setup</h2>
<p>For this tutorial, we’re using Windows 10 and Python 3.10.</p>
<p>Elastic Security Labs is releasing a set of tools to automate the unpacking process and help analysts and the community respond to ICEDID.</p>
<table>
<thead>
<tr>
<th>Script</th>
<th>Description</th>
<th>Compatibility</th>
</tr>
</thead>
<tbody>
<tr>
<td>decrypt_file.py</td>
<td>Decrypt ICEDID encrypted file</td>
<td>Windows and others (not tested)</td>
</tr>
<tr>
<td>gzip_variant/extract_gzip.py</td>
<td>Extract payloads from ICEDID fake GZip file</td>
<td>Windows and others (not tested)</td>
</tr>
<tr>
<td>gzip_variant/extract_payload_from_core.py</td>
<td>Extract and decrypt payloads from the rebuilt ICEDID core binary</td>
<td>Windows and others (not tested)</td>
</tr>
<tr>
<td>gzip_variant/load_core.py</td>
<td>Load and execute core custom PE binary</td>
<td>Windows only</td>
</tr>
<tr>
<td>gzip_variant/read_configuration.py</td>
<td>Read ICEDID configuration file contained in the fake GZip</td>
<td>Windows and others (not tested)</td>
</tr>
<tr>
<td>rebuild_pe.py</td>
<td>Rebuild a PE from ICEDID custom PE file</td>
<td>Windows and others (not tested)</td>
</tr>
</tbody>
</table>
<p>In order to use the tools, clone the <a href="https://github.com/elastic/labs-releases">Elastic Security Lab release repository</a> and install the nightMARE module.</p>
<pre><code>git clone https://github.com/elastic/labs-releases
cd labs-release
pip install .\nightMARE\
</code></pre>
<blockquote>
<p>All tools in this tutorial use the <strong>nightMARE</strong> module, this library implements different algorithms we need for unpacking the various payloads embedded within ICEDID. We’re releasing nightMARE because it is required for this ICEDID analysis, but stay tuned - more to come as we continue to develop and mature this framework.</p>
</blockquote>
<h2>Unpacking the fake GZip</h2>
<p>The ICEDID fake GZip is a file that <a href="https://attack.mitre.org/techniques/T1036/008/">masquerades</a> as a valid GZip file formatted by encapsulating the real data with a <a href="https://docs.fileformat.com/compression/gz/">GZip header and footer</a>.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/unpacking-icedid/image20.jpg" alt="GZip header and footer" /></p>
<p>GZip magic bytes appear in red.<br />
The GZip header is rendered in green.<br />
The dummy filename value is blue.</p>
<p>After the GZip header is the true data structure, which we describe below.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/unpacking-icedid/image19.jpg" alt="FakeGzip data structure" /></p>
<p>We will use the <strong>labs-releases\tools\icedid\gzip-variant\extract_gzip.py</strong> script to unpack this fraudulent GZip.</p>
<pre><code>usage: extract_gzip.py [--help] input output

positional arguments:
  input       Input file
  output      Output directory

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

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

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

positional arguments:
  input       Input file
  output      Output file

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

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

positional arguments:
  input       Input file

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

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

positional arguments:
  input                 Input file
  output                Output reconstructed PE

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

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

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

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

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

positional arguments:
  input       Input file
  output      Output directory

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

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

python .\rebuild_pe.py .\core_extract\browser_hook_payload_1.cpe .\core_extract\browser_hook_payload_1.bin
</code></pre>
<p>Now we have two PE binaries ( <strong>browser_hook_payload_0.bin</strong> and <strong>browser_hook_payload_1.bin</strong> ) we can further analyze.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/unpacking-icedid/image9.jpg" alt="Payloads for further analysis" /></p>
<p>Attentive readers may observe that we have skipped the <strong>VNC server</strong> unpacking from the core binary, a decision we made intentionally. We will release it along with other tools in upcoming research, so stay tuned!</p>
<h2>Conclusion</h2>
<p>In this tutorial we covered ICEDID GZip variant unpacking, starting with the extraction of the fake GZip binary, followed by the reconstruction of the core binary and unpacking its payloads.</p>
<p>ICEDID is constantly evolving, and we are going to continue to monitor major changes and update our tooling along with our research. Feel free to <a href="https://github.com/elastic/labs-releases/issues">open an issue</a> or <a href="mailto:threat-notification@elastic.co">send us a message</a> if something is broken or doesn’t work as expected.</p>
<p>Elastic Security Labs is a team of dedicated researchers and security engineers focused on disrupting adversaries through the publication of detailed detection logic, protections, and applied threat research.</p>
<p>Follow us on <a href="https://twitter.com/elasticseclabs">@elasticseclabs</a>and visit our research portal for more resources and research.</p>
<h2>References</h2>
<p>The following were referenced throughout the above research:</p>
<ul>
<li><a href="https://www.elastic.co/pdf/elastic-security-labs-thawing-the-permafrost-of-icedid.pdf">https://www.elastic.co/pdf/elastic-security-labs-thawing-the-permafrost-of-icedid.pdf</a></li>
<li><a href="https://securityintelligence.com/new-banking-trojan-icedid-discovered-by-ibm-x-force-research/">https://securityintelligence.com/new-banking-trojan-icedid-discovered-by-ibm-x-force-research/</a></li>
<li><a href="https://www.justice.gov/opa/pr/emotet-botnet-disrupted-international-cyber-operation">https://www.justice.gov/opa/pr/emotet-botnet-disrupted-international-cyber-operation</a></li>
<li><a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.darkvnc">https://malpedia.caad.fkie.fraunhofer.de/details/win.darkvnc</a></li>
<li><a href="https://www.cybereason.com/blog/threat-analysis-report-all-paths-lead-to-cobalt-strike-icedid-emotet-and-qbot">https://www.cybereason.com/blog/threat-analysis-report-all-paths-lead-to-cobalt-strike-icedid-emotet-and-qbot</a></li>
<li><a href="https://github.com/elastic/labs-releases">https://github.com/elastic/labs-releases</a></li>
<li><a href="https://github.com/hasherezade/funky_malware_formats/blob/f1cacba4ee347601dceacda04e4de8c699971d29/iced_id_parser/iceid_to_pe.cpp">https://github.com/hasherezade/funky_malware_formats/blob/f1cacba4ee347601dceacda04e4de8c699971d29/iced_id_parser/iceid_to_pe.cpp</a></li>
<li><a href="https://mh-nexus.de/en/hxd/">https://mh-nexus.de/en/hxd/</a></li>
<li><a href="https://hex-rays.com/IDA-pro/">https://hex-rays.com/IDA-pro/</a></li>
</ul>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/security-labs/assets/images/unpacking-icedid/photo-edited-07@2x.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[The Elastic Container Project for Security Research]]></title>
            <link>https://www.elastic.co/security-labs/the-elastic-container-project</link>
            <guid>the-elastic-container-project</guid>
            <pubDate>Wed, 01 Mar 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[The Elastic Container Project provides a single shell script that will allow you to stand up and manage an entire Elastic Stack using Docker. This open source project enables rapid deployment for testing use cases.]]></description>
            <content:encoded><![CDATA[<h2>Preamble</h2>
<p>The Elastic Stack is a modular data analysis ecosystem. While this allows for engineering flexibility, it can be cumbersome to stand up a development instance for testing. The easiest way to stand up the Elastic Stack, is to use <a href="https://cloud.elastic.co">Elastic Cloud</a> - it’s completely turnkey. However, there could be situations where Elastic Cloud won’t work for your testing environment. To help with this, this blog will provide you with the necessary information required in order to quickly and painlessly stand up a local, fully containerized, TLS-secured, Elastic Stack with Fleet and the Detection Engine enabled. You will be able to create a Fleet policy, install an Elastic Agent on a local host or VM, and send the data into your stack for monitoring or analysis.</p>
<p>This blog will cover the following:</p>
<ul>
<li>The Elastic Stack</li>
<li>The Elastic Container project</li>
<li>How to use the Elastic Container project</li>
<li>How to navigate Kibana and use its related features for security research</li>
</ul>
<blockquote>
<p>The Elastic Container Project is not sponsored or maintained by the company, Elastic. Design and implementation considerations for the project may not reflect Elastic’s guidance on deploying a production-ready stack.</p>
</blockquote>
<h2>The Elastic Stack</h2>
<p>The Elastic Stack is made up of several different components, each of which provide a distinct capability that can be utilized across a wide variety of use cases.</p>
<h3>Elasticsearch</h3>
<p>Elasticsearch is a distributed, RESTful search and analytics engine. As the heart of the Elastic Stack, it centrally stores your data for lightning-fast search, fine-tuned relevancy, and powerful analytics that scale with ease.</p>
<h3>Kibana</h3>
<p>Kibana is the user interface that lets you visualize your Elasticsearch data and manage the Elastic Stack.</p>
<h3>The Elastic Agent</h3>
<p>The Elastic Agent is the modular agent that allows you to collect data from an endpoint or act as a vehicle to ship data from 3rd party sources, like threat feeds. The Elastic Security integration for endpoints prevents ransomware and malware, detects advanced threats, and arms responders with vital investigative context.</p>
<h2>The Elastic Container Project</h2>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/elastic-container.png" alt="The Elastic Container Project" /></p>
<p>As mentioned above, the Elastic Stack is modular which makes it very flexible for a wide variety of use cases but this can add complexity to the implementation.</p>
<p>The Elastic Container project is an open source project that uses Docker Compose as a way to stand up a fully-functional Elastic Stack for use in non-production environments. This project is not sponsored or maintained by the Elastic company.</p>
<h3>Introduction</h3>
<p>The <a href="https://github.com/peasead/elastic-container">Elastic Container Project</a> includes three main components:</p>
<ul>
<li>Elasticsearch</li>
<li>Kibana</li>
<li>the Elastic Agent</li>
</ul>
<p>The project leverages <a href="https://docs.docker.com/compose/">Docker Compose</a>, which is a tool to build, integrate, and manage multiple Docker containers.</p>
<p>To simplify the management of the containers, the project includes a shell script that allows for the staging, starting, stopping, and destroying of the containers.</p>
<p>Additionally, the project makes use of self-signed TLS certificates between Elasticsearch and Kibana, Kibana and your web browser, the Elastic Agent and Elasticsearch, and the Elastic Agent and Kibana.</p>
<h3>Prerequisites</h3>
<p>The project was built and tested on Linux and macOS operating systems. If you are using Windows, you’ll not be able to use the included shell script, but you can still run native Docker Compose commands and manually perform post-deployment steps.</p>
<p>While not thoroughly tested, it is recommended that you contribute 4 cores and 8 GB of RAM to Docker.</p>
<p>There are only a few packages you need to install:</p>
<ul>
<li>Docker</li>
<li>Docker Compose</li>
<li>jq</li>
<li>Git</li>
<li>cURL</li>
</ul>
<h4>macOS</h4>
<p>If you’re running on macOS, you can install the prerequisites using <a href="https://brew.sh/">Homebrew</a>, which is an open-source package management system for macOS. Check out the Homebrew site for information on installing it if needed.</p>
<pre><code>**brew install jq git**
**brew install --cask docker**
</code></pre>
<h4>Linux</h4>
<p>If you’re running on Linux, you can install the prerequisites using your package management system ( <strong>DNF</strong> , <strong>Yum</strong> , or <strong>APT</strong> ).</p>
<p><strong>RPM-based distributions</strong></p>
<pre><code>**dnf install jq git curl**
</code></pre>
<p><strong>Ubuntu</strong></p>
<pre><code>**apt-get install jq git curl**
</code></pre>
<p>You'll also need the Docker suite (including the <strong>docker-compose-plugin</strong> ). Check out Docker's <a href="https://docs.docker.com/engine/install/">installation instructions</a> for your OS'</p>
<h3>Cloning the project repository</h3>
<p>The Elastic Container project is stored on Github. As long as you have Git installed, you can collect it from your CLI of choice.</p>
<pre><code>**git clone https://github.com/peasead/elastic-container.git**
**cd elastic-container**
</code></pre>
<p>This repository includes everything needed to stand up the Elastic Stack containers using a single shell script.</p>
<h3>Setting credentials</h3>
<p>Before proceeding, ensure you update the credentials for the Elastic and Kibana accounts in the <strong>.env</strong> file located in the root directory of the repository from their defaults of <strong>changeme</strong>.</p>
<h3>The shell script</h3>
<p>As mentioned above, the project includes a shell script that will simplify the management of the containers.</p>
<pre><code>**usage: ./elastic-container.sh [-v] (stage|start|stop|restart|status|help)**
**actions:**
 **stage downloads all necessary images to local storage**
 **start creates network and starts containers**
 **stop stops running containers without removing them**
 **destroy stops and removes the containers, the network and volumes created**
 **restart simply restarts all the stack containers**
 **status check the status of the stack containers**
 **help print this message**
 **flags:**
 **-v enable verbose output**
</code></pre>
<h4>Stage</h4>
<p>This option downloads all of the containers from the Elastic Docker hub. This is useful if you are going to be building the project on a system that does not always have Internet access. This is not required, you can skip this option and move directly to the start option, which will download the containers.</p>
<pre><code>**$ ./elastic-container.sh stage**
**8.3.0: Pulling from elasticsearch/elasticsearch**
**7aabcb84784a: Already exists**
**e3f44495617d: Downloading [====\\&gt;] 916.5kB/11.26MB**
**52008db3f842: Download complete**
**551b59c59fdc: Downloading [\\&gt;] 527.4kB/366.9MB**
**25ee26aa662e: Download complete**
**7a85d02d9264: Download complete**
**…**
</code></pre>
<h4>Start</h4>
<p>This opinion will create the container network, download all of the required containers, set up the TLS certificates, and start and connect Elasticsearch, Kibana, and the Fleet server containers together. This option is a “quick start” to get the Elastic Stack up and running. If you have not changed your credentials in the .env file from the defaults, the script will exit.</p>
<pre><code>**$ ./elastic-container.sh start**

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

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

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

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

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

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

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

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

Browse to https://localhost:5601
Username: elastic
Passphrase: you-changed-me-from-the-default-right?**
</code></pre>
<h3>Accessing the Elastic Stack</h3>
<p>Once the containers have all downloaded and started, you’ll get an output that tells you to browse to <strong><a href="https://localhost:5601">https://localhost:5601</a></strong>.</p>
<p><strong>Note:</strong> You’ll need to accept the self-signed TLS certificate.</p>
<h2>Enabling the Platinum Features</h2>
<p>Enabling the Platinum license features are completely optional. Security features, like anti-malware, EDR, EPP, etc. are included in the Basic license. Memory, behavior, and ransomware protections are Platinum license features. If you want to change your license, we can do that with the <strong>.env</strong> file or from within Kibana. You can update to Elastic Platinum for 30-days.</p>
<p>If you want to use the <strong>.env</strong> file so that the features are enabled when the stack is built, change <strong>LICENSE=basic</strong> to <strong>LICENSE=trial</strong> and then start the project as normal.</p>
<p>If you prefer to use Kibana, click on the hamburger menu, and then click on Stack Management.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image5.jpg" alt="Access Stack Management from Kibana" /></p>
<p>Click on License Management and then “Start a 30-day trial”.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image24.png" alt="Start a 30-day trial" /></p>
<h2>Creating a Fleet policy</h2>
<p>Now that we have the entire Elastic Stack up and running, we can make a <a href="https://www.elastic.co/guide/en/kibana/current/fleet.html">Fleet</a> policy. Fleet is a subroutine of an <a href="https://www.elastic.co/elastic-agent">Elastic Agent</a> (which was built when we ran the <strong>start</strong> option in the shell script) that enables you to manage other Elastic Agents, policies, and integrations.</p>
<blockquote>
<p>Fleet is managed in Kibana, the UI that allows you to interact with data stored in Elasticsearch and manage your Elastic stack. If you’re interested in learning more about Kibana, check out the <a href="https://www.elastic.co/training/free#quick-starts">free</a> <a href="https://www.elastic.co/training/free#how-to">training</a> <a href="https://www.elastic.co/training/free#fundamentals">videos</a>.</p>
</blockquote>
<p>Log into your Kibana instance and click on the “hamburger” menu on the top left, and navigate down to “Fleet”, under the “Management” section.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image17.jpg" alt="Accessing Fleet" /></p>
<p>Next, click on the “Agent policies” tab and then the “Create agent policy” button.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image27.png" alt="Create agent policy" /></p>
<p>Give your new policy a name and a description (optional). Normally, we uncheck the “Collect agent logs” and “Collect agent metrics” options because it’s additional data going to the stack that we generally don’t need for our specific use-case. If you’re doing troubleshooting or interested in what’s happening behind the scenes, this data can help you understand that.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/Agent_policies_-_Fleet_-_Elastic.jpg" alt="Defining the agent policy" /></p>
<p>Next, click on your new policy and the blue “Add integration” button.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image15.png" alt="Open the Fleet policy" /></p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image3.jpg" alt="Add integrations" /></p>
<p>There are hundreds of integrations, but the ones that we’re most interested in for this blog are for Elastic Security.</p>
<p>To install Elastic Security, simply click on the tile on the main integrations page or search for “security”.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image16.png" alt="Endpoint and Cloud Security integration" /></p>
<p>Next, click the “Add Endpoint and Cloud Security” button to install this integration into the policy we just created.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image4.jpg" alt="Add Endpoint and Cloud Security" /></p>
<p>Name the integration and click the blue “Save and continue” button.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image1.jpg" alt="Save the integration to the policy" /></p>
<blockquote>
<p>While the Endpoint and Cloud Security and System integrations will collect security related logs, if you’re using Sysmon on a Windows host, you may want to add the “Windows” integration to collect those logs.</p>
</blockquote>
<p>Once the integration is installed, you’ll be prompted to add more Agents or to do that later. Select the “Add Elastic Agent later” option so we can make a few more changes to our policy.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image19.jpg" alt="Add Elastic Agents later" /></p>
<p>Now we’ll be dropped back to our policy page.</p>
<p>We should have two integrations for our policy: <strong>security</strong> and <strong>system-1</strong>.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/Agent_policies_-_Fleet_-_Elastic.jpg" alt="Reviewing the Windows policy" /></p>
<p>Before we add any agents, we’ll want to set our Elastic Agent to Detect (so that it allows the malware to completely execute), register the Elastic Agent as a trusted AV solution (Windows only), and instruct the Endpoint and Cloud Security integration to collect memory samples from security events. This is tremendously helpful for “fileless” malware that injects directly into memory, like Cobalt Strike.</p>
<blockquote>
<p>If you want to learn more about extracting malware beacons from events generated by the Elastic Agent, check out our other <a href="https://www.elastic.co/security-labs/collecting-cobalt-strike-beacons-with-the-elastic-stack">publications</a> and <a href="https://github.com/elastic/malware-exquacker">repositories</a>.</p>
</blockquote>
<p>To allow the malware to continue to execute, on your “Windows” policy page, click on the name of the integration (“security” in our example), set the Protection level to “Detect”.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image25.jpg" alt="Setting the Protection level to Detect" /></p>
<p>Repeat these steps for the Ransomware, Memory threat protections, and Malicious behavior sections.</p>
<blockquote>
<p>We’re setting the Elastic Agent to Detect so that the malware we’re detonating will run completely so that we can analyze the entire execution chain. If you want the malware to be stopped, you can leave this in Prevent mode.</p>
</blockquote>
<p>Next, scroll to the bottom and select the “Register as antivirus” toggle and click on the “Show advanced settings” hyperlink.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image18.jpg" alt="Register as antivirus" /></p>
<p>Scroll down to <strong>windows.advanced.memory_protection.shellcode_collect_sample</strong> , <strong>windows.advanced.memory_protection.memory_scan_collect_sample</strong> , and <strong>windows.advanced.memory_protection.shellcode_enhanced_pe_parsing</strong> options and set the value to <strong>true</strong>.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image26.jpg" alt="Enabling sample collection" /></p>
<blockquote>
<p>As mentioned above, these steps are for labs, sandboxes, testing, etc. These settings can generate a lot of data, so setting these for production will need resourcing and sizing considerations.</p>
</blockquote>
<p>If you’re making a policy for Linux or macOS, repeat these for the proper OS.</p>
<p>Once we’re done with all of the post-installation configurations, we can click the blue Save integration button.</p>
<h2>Enabling Elastic’s Prebuilt Detection Rules</h2>
<p>Now that we have created our Fleet agent policy we need to enable the set of pre-built detection rules associated with the OS or platform we will be deploying on (e.g Windows). To do this you will need to go to the Alerts page within the security app.</p>
<p>Click on the hamburger menu and select Alerts, under the Security solution.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/Home_-_Elastic.jpg" alt="Access the Alerts section" /></p>
<p>Next, click on the blue Manage Rules button.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/Alerts_-_Kibana.jpg" alt="Access the Manage rules interface" /></p>
<p>Once on the Rules page you can update all of the prebuilt rules provided by Elastic by clicking on the “Update Elastic prebuilt rules” button. The update framework is enabled when you go into the “Manage rules” section for the first time, if the “Update Elastic prebuilt rules” button isn’t present, refresh the screen.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/Rules_-_Kibana.jpg" alt="Update Elastic prebuilt rules" /></p>
<p>Once the rules have been updated, you can browse the available detection rules, search them by a number of different patterns or simply filter by tag, which is what we will do here by searching for Windows rules.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/Rules_-_Kibana-2.jpg" alt="Filter for Windows rules" /></p>
<p>Now we can select all of the Windows rules.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/Rules_-_Kibana-3.jpg" alt="Selecting all Windows rules" /></p>
<p>Once all of the rules have been selected, we can bulk enable them.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/Rules_-_Kibana-4.jpg" alt="Bulk enable Windows rules" /></p>
<blockquote>
<p>As the Elastic Container Project runs completely inside single Docker containers, performance impacts could be noticed if you enable all of the rules available. Explore the different rules and enable or disable them based on your infrastructure and use cases.</p>
</blockquote>
<p>After we have enabled these rules they will be live and will be run against the data your endpoint agent sends into your stack. When the Detection Engine rules are triggered, they will be raised in the Alerts page in the Security Solution.</p>
<h2>Enrolling an Elastic Agent</h2>
<p>Still in Fleet, we have several ways to add an Elastic Agent. The most straightforward is from within the policy that we want to enroll an Elastic Agent into (otherwise you have to specify which policy you want to use). It doesn’t really matter which approach you use, but clicking on the Actions button and then Add agent works from just about anywhere in Fleet.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image8.jpg" alt="Adding Elastic Agent" /></p>
<p>Scroll down and click on the OS that you’re going to be installing the Elastic Agent on, and copy/paste the instructions directly into a terminal window on the host you’re going to be installing the agent onto. Note, if you’re using Windows, use a Powershell CLI that is running as (or elevated to) an account with administrative entitlements.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image22.png" alt="Powershell commands to add an Elastic Agent" /></p>
<p>Of note, because all of our TLS certificates are self-signed, we need to append the <strong>–insecure</strong> flag. This is unnecessary if you are using trusted certificates.</p>
<pre><code>**.\elastic-agent.exe install --url=https://[stack-ip]:8220 --enrollment-token=[token] --insecure**
</code></pre>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image23.jpg" alt="Enrolling the Elastic Agent into Fleet" /></p>
<p>Back in Kibana, we can see confirmation that the Elastic Agent installed on the host and that data is being recorded into Elasticsearch.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image2.jpg" alt="Verifying Elastic Agent enrollment" /></p>
<p>We can see that the Elastic Agent is reporting into Fleet and is healthy.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image28.png" alt="Verify Elastic Agent health" /></p>
<p>If we go into the Discover tab, we can see various event types reporting into Elasticsearch. We can generate some test data by opening <strong>notepad.exe</strong> , <strong>calc.exe</strong> , and <strong>ping.exe -t <a href="http://www.elastic.co">www.elastic.co</a></strong> on the host. From Discover, we can make a simple query to validate that we’re seeing the data:</p>
<pre><code>**process.name.caseless : (notepad.exe or ping.exe or calc.exe)**
</code></pre>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image7.png" alt="Verifying data is being sent to Elasticsearch" /></p>
<p>Now that we’ve validated that we’re seeing data. Let's fire some malware!</p>
<h2>Test fire some malware</h2>
<p>There are a lot of places you can download malware from, but for this test, we’ll simply use the industry standard <a href="https://www.eicar.org/download-anti-malware-testfile/">EICAR anti malware test file</a> to check the functionality.</p>
<p>The EICAR test is a file that is universally identified by security vendors and is used to test the operation of anti malware software and platforms. It contains a single string and is non-malicious.</p>
<p>From within the Windows host, we’ll use Powershell to download the EICAR file.</p>
<pre><code>**Invoke-WebRequest -Uri &quot;https://secure.eicar.org/eicar.com.txt&quot; -OutFile &quot;eicar.txt&quot;**
</code></pre>
<p>As expected, the event was immediately identified by the Elastic Agent’s security integration.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image29.jpg" alt="Elastic Security detected the EICAR test file" /></p>
<p>After a few minutes, the events are recorded into the Security Solution within Kibana. You can get there by clicking on the hamburger menu and then clicking on the Alerts section.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image9.jpg" alt="Viewing Security alerts" /></p>
<p>Here we can see the alert populated.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image11.png" alt="Alert in the Security Solution" /></p>
<p>If we click on the Analyzer button, we can dig into the event to identify the process that generated the event.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image12.jpg" alt="Analyzer button" /></p>
<p>In our example, we can see <strong>powershell.exe</strong> generated the event and this includes the correlated network events - <strong>secure.eicar.org</strong> , which is where the EICAR test file was downloaded from.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/image13.jpg" alt="Analyzer view" /></p>
<h2>Summary</h2>
<p>In this publication, we introduced you to the Elastic Stack and an open source project that can be used to quickly and securely stand up the entire stack for testing, labs, and security research.</p>
<p>Kibana and the Security Solution are powerful tools that are built by incident responders, threat hunters, and intelligence analysts with security practitioners in mind. To learn more about how to use these tools, <a href="https://www.elastic.co/training/">Elastic has some great (free and paid) training</a> that can help learn how to use Kibana for threat hunting.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/security-labs/assets/images/the-elastic-container-project/blog-thumb-container-barge.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[NETWIRE Dynamic Configuration Extraction]]></title>
            <link>https://www.elastic.co/security-labs/netwire-dynamic-configuration-extraction</link>
            <guid>netwire-dynamic-configuration-extraction</guid>
            <pubDate>Mon, 30 Jan 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic Security Labs discusses the NETWIRE trojan and is releasing a tool to dynamically extract configuration files.]]></description>
            <content:encoded><![CDATA[<h2>Key takeaways</h2>
<ul>
<li>NETWIRE has shown an increase in prevalence over the last year</li>
<li>Elastic Security Labs created an extractor to pull out configuration data from NETWIRE files and memory dumps targeting the functions the malware uses to extract its encrypted data</li>
<li>The NETWIRE extractor is freely available for download</li>
</ul>
<blockquote>
<p>To download the NETWIRE configuration extractor, check out our post on the tool:</p>
<ul>
<li><a href="https://www.elastic.co/security-labs/netwire-configuration-extractor">NETWIRE configuration extractor</a></li>
</ul>
</blockquote>
<h2>Preamble</h2>
<p><a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.netwire">NETWIRE</a> is a Remote Access Tool (RAT) that has been used since at least 2014. It is a publicly available commodity malware and has been observed being used by financially motivated and nation-state actors.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/netwire-dynamic-configuration-extraction/image1.jpg" alt="NETWIRE observations over the past 12-months" /></p>
<p>In the second half of 2022, we noticed an uptick in the prevalence of NETWIRE usage in our telemetry data. This prompted the Elastic Security Labs team to develop a configuration extractor to assist the security community in collecting atomic indicators within the configurations. Using this extractor will support threat tracking and improve detection, prevention, and response times.</p>
<h2>Extractor</h2>
<p>The NETWIRE RAT uses the <a href="https://en.wikipedia.org/wiki/RC4">RC4 symmetric encryption</a> algorithm to protect its configuration which is encrypted in the <strong>.data</strong> section along with the 16 bytes long RC4 decryption key.</p>
<p>While reversing our samples the analysts noticed that for both the <strong>crypto::rc4_init_sbox</strong> and <strong>crypto::rc4_decrypt</strong> functions the second argument (#2 in the image below) is always a memory address for the desired encrypted configuration value, and the third argument (#3) is an immediate value written to the memory stack before the call which represents the size of the encrypted string.</p>
<p>It was also noted that the function calls are one after the other. This is important to allow us to structure the extractor to look for these functions sequentially.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/netwire-dynamic-configuration-extraction/image4.png" alt="NETWIRE's assembly code for the decryption function" /></p>
<p>With <strong>$key</strong> (from the above image) in mind, we created YARA rules to identify the location of the key and encrypted configuration values.</p>
<p>![YARA rule section that identifies the key and encrypted configuration](/assets/images/netwire-dynamic-configuration-extraction/image5.jpg</p>
<p>With this information we can then use <a href="http://www.capstone-engine.org/">Capstone</a> to:</p>
<ol>
<li>
<p>Locate the function responsible for decrypting the configuration using YARA.</p>
</li>
<li>
<p>Disassemble the function using Capstone.</p>
</li>
<li>
<p>Extract the RC4 key address and the encrypted configuration field addresses.</p>
</li>
<li>
<p>Extract the size of the configuration field.</p>
</li>
<li>
<p>RC4 decrypt the encrypted fields and rebuild the configuration.</p>
</li>
</ol>
<p><img src="https://www.elastic.co/security-labs/assets/images/netwire-dynamic-configuration-extraction/image2.jpg" alt="Locating the RC4 key address and the encrypted configuration" /></p>
<p>![RC4 decrypting the configuration](/assets/images/netwire-dynamic-configuration-extraction/image5.jpg</p>
<p>Once we have recreated the configuration, we can use the extractor to pull out several parameters used by NETWIRE, as well as a few basic file characteristics:</p>
<ul>
<li><strong>Active Setup Key</strong> : <a href="https://attack.mitre.org/techniques/T1547/014/">Active Setup</a> registry key to achieve persistence.</li>
<li><strong>C2 IP list</strong> : List of command and control (C2) server domains or IP addresses.</li>
<li><strong>Host ID</strong> : A unique identifier that is assigned to the infected machine.</li>
<li><strong>Installation path</strong> : The location where the malware will be installed.</li>
<li><strong>Keylogger logs directory</strong> : The location where the keylogging log file will be stored.</li>
<li><strong>Mutex</strong> : Mutex name, to create a synchronization object to ensure only one instance of the sample is running on the machine.</li>
<li><strong>Password</strong> : Static password to generate AES key used for encrypting the communication between the malware and the C2 server.</li>
<li><strong>Run registry key entry</strong> : Name of the entry in the <a href="https://attack.mitre.org/techniques/T1547/001/">run registry</a>, used for persistence.</li>
<li><strong>Sleep in seconds</strong> : The amount of time the malware sleeps.</li>
</ul>
<p><img src="https://www.elastic.co/security-labs/assets/images/netwire-dynamic-configuration-extraction/image6.jpg" alt="Sample output from configuration extractor" /></p>
<p>The configuration extractor accepts four parameters:</p>
<ul>
<li><strong>-f</strong> : to specify a single NETWIRE sample</li>
<li><strong>-d</strong> : To specify a directory of NETWIRE samples</li>
<li><strong>-o</strong> : To write the configuration in JSON format to the specified file</li>
<li><strong>--all-config</strong> : To print the unparsed raw decrypted configuration</li>
</ul>
<h2>Analysis</h2>
<p>We’ve used this extractor to examine a set of samples from the previous 180 days to extract indicators for further enrichment and analysis.</p>
<p>Our initially collected batch of samples came as a mixture of executable files and memory dumps. The extractor will only work on unmapped files, so the dumps which were already mapped were run through <a href="https://github.com/hasherezade/pe_unmapper"><strong>pe_unmapper</strong></a>.</p>
<p>When extracting a payload from memory, we are obtaining a memory-mapped version of it. This means that the <strong>&quot;Raw Address&quot;</strong> and <strong>&quot;Raw Size&quot;</strong> may not be correctly aligned with the correct section’s data. To correctly align the PE file, it is necessary to adjust the pointer to the raw address so that it matches the virtual address for every section.</p>
<p>Now we can run the configuration extractor with <a href="https://python-poetry.org/">Poetry</a> against our directory of unmapped binaries:</p>
<pre><code>**poetry lock**
**poetry install**
**poetry shell**
**netwire-config-extractor -d sample-dir/ -o output.ndjson**
</code></pre>
<p>This file, <strong>output.ndjson</strong> , can then be uploaded to Kibana for further analysis.</p>
<blockquote>
<p>Check out the <a href="https://www.elastic.co/security-labs/the-elastic-container-project">Elastic Container project</a> to quick spin up an Elastic Stack and start analyzing structured security-relevant data.</p>
</blockquote>
<p><img src="https://www.elastic.co/security-labs/assets/images/netwire-dynamic-configuration-extraction/image3.png" alt="Extracted NETWIRE configuration data" /></p>
<p>Next time you run into a NETWIRE sample, run it through our configuration extractor to pull out other indicators to help you on your analytic journey or begin remediating quicker.</p>
<h2>Detection</h2>
<h3>YARA</h3>
<p>These YARA rules can used to detect and identify NETWIRE RAT.</p>
<pre><code>rule Windows_Trojan_Netwire_1 {
   meta:
       author = &quot;Elastic Security&quot;
       os = &quot;Windows&quot;
       arch = &quot;x86&quot;
       category_type = &quot;Trojan&quot;
       family = &quot;Netwire&quot;
       threat_name = &quot;Windows.Trojan.Netwire&quot;
   strings:
       $a = { 0F B6 74 0C 10 89 CF 29 C7 F7 C6 DF 00 00 00 74 09 41 89 F3 88 5C }
   condition:
       all of them
}
rule Windows_Trojan_Netwire_2 {
   meta:
       author = &quot;Elastic Security&quot;
       os = &quot;Windows&quot;
       arch = &quot;x86&quot;
       category_type = &quot;Trojan&quot;
       family = &quot;Netwire&quot;
       threat_name = &quot;Windows.Trojan.Netwire&quot;
   strings:
       $a1 = &quot;[%.2d/%.2d/%d %.2d:%.2d:%.2d]&quot; fullword
       $a2 = &quot;\\Login Data&quot;
       $a3 = &quot;SOFTWARE\\NetWire&quot; fullword
   condition:
       2 of them
}
rule Windows_Trojan_Netwire_3 {
   meta:
       author = &quot;Elastic Security&quot;
       os = &quot;Windows&quot;
       arch = &quot;x86&quot;
       category_type = &quot;Trojan&quot;
       family = &quot;Netwire&quot;
       threat_name = &quot;Windows.Trojan.Netwire&quot;
   strings:
       $a = { C9 0F 44 C8 D0 EB 8A 44 24 12 0F B7 C9 75 D1 32 C0 B3 01 8B CE 88 44 }
   condition:
       all of them
}
rule Windows_Trojan_Netwire_4 {
   meta:
       author = &quot;Elastic Security&quot;
       os = &quot;Windows&quot;
       arch = &quot;x86&quot;
       category_type = &quot;Trojan&quot;
       family = &quot;Netwire&quot;
       threat_name = &quot;Windows.Trojan.Netwire&quot;
   strings:
       $a1 = &quot;http://%s%ComSpec&quot; ascii fullword
       $a2 = &quot;%c%.8x%s&quot; ascii fullword
       $a3 = &quot;%6\\6Z65dlNh\\YlS.dfd&quot; ascii fullword
       $a4 = &quot;GET %s HTTP/1.1&quot; ascii fullword
       $a5 = &quot;R-W65: %6:%S&quot; ascii fullword
       $a6 = &quot;PTLLjPq %6:%S -qq9/G.y&quot; ascii fullword
   condition:
       4 of them
}
</code></pre>
<h2>Indicators</h2>
<p>All indicators are also available <a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blte3d9f2700cdf6637/63d3f854e4e29e75dc5de351/9965-indicators.zip">for download</a> in both ECS and STIX format in a combined zip bundle.</p>
<p>The following indicators were discussed in this research.</p>
<table>
<thead>
<tr>
<th>Indicator</th>
<th>Type</th>
<th>Note</th>
</tr>
</thead>
<tbody>
<tr>
<td>139.28.38[.]235</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>149.102.132[.]253</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>184.75.221[.]115</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>185.136.165[.]182</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>185.140.53[.]139</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>185.140.53[.]144</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>185.140.53[.]154</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>185.140.53[.]61</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>185.216.71[.]251</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>194.36.111[.]59</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>194.5.98[.]126</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>194.5.98[.]178</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>194.5.98[.]188</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>194.5.98[.]65</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>212.193.29[.]37</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>212.193.30[.]230</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>213.152.161[.]249</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>217.151.98[.]163</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>23.105.131[.]166</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>37.0.14[.]199</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>37.0.14[.]203</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>37.0.14[.]206</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>37.0.14[.]208</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>37.0.14[.]214</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>37.120.217[.]243</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>51.161.104[.]138</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>54.145.6[.]146</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>80.66.64[.]136</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>85.209.134[.]105</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>85.31.46[.]78</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>94.156.35[.]40</td>
<td>ipv4-addr</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>20220627.duckdns[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>admin96.hopto[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>alice2019.myftp[.]biz</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>asorock1111.ddns[.]net</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>banqueislamik.ddrive[.]online</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>betterday.duckdns[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>bigman2021.duckdns[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>blazeblaze.ddns[.]net</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>chongmei33.myddns[.]rocks</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>clients.enigmasolutions[.]xyz</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>gracedynu.gleeze[.]com</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>ingobea.hopto[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>iphanyi.edns[.]biz</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>iphy.strangled[.]net</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>kimlee11.duckdns[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>loffgghh.duckdns[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>megaton.gleeze[.]com</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>moran101.duckdns[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>netuwaya.servecounterstrike[.]com</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>nowancenorly.ddns[.]net</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>podzeye.duckdns[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>podzeye2.duckdns[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>recoveryonpoint.duckdns[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>redlinea[.]top</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>roller.duckdns[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>rozayleekimishere.duckdns[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>sani990.duckdns[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>saturdaylivecheckthisout.duckdns[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>uhie.hopto[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>uhie2020.duckdns[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>wcbradley.duckdns[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>xman2.duckdns[.]org</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
<tr>
<td>zonedx.ddns[.]net</td>
<td>domain-name</td>
<td>NETWIRE RAT C2</td>
</tr>
</tbody>
</table>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/security-labs/assets/images/netwire-dynamic-configuration-extraction/lock-code-combination-configuration.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[NETWIRE Configuration Extractor]]></title>
            <link>https://www.elastic.co/security-labs/netwire-configuration-extractor</link>
            <guid>netwire-configuration-extractor</guid>
            <pubDate>Fri, 27 Jan 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Python script to extract the configuration from NETWIRE samples.]]></description>
            <content:encoded><![CDATA[<p>Python script to extract the payload from NETWIRE samples.</p>
<p><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltdcef1d05d2077d05/63d43627c31a7126813ff8b6/netwire-configuration-extractor.tar.gz">Download netwire-configuration-extractor.tar.gz</a></p>
<blockquote>
<p>For information on the NETWIRE malware check out the following resources:</p>
<ul>
<li><a href="https://www.elastic.co/security-labs/netwire-dynamic-configuration-extraction">NETWIRE Dynamic Configuration Extraction</a></li>
</ul>
</blockquote>
<h2>Getting started</h2>
<h3>Docker</h3>
<p>The recommended and easiest way to get going is to use Docker. From the directory this README is in, you can build a local container.</p>
<pre><code>docker build . -t netwire_loader_config_extractor
</code></pre>
<p>Then we run the container with the <strong>-v</strong> flag to map a host directory to the docker container directory.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data netwire_loader_config_extractor:latest --help
</code></pre>
<h3>Running it locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
netwire-config-extractor --help
</code></pre>
<h2>Usage</h2>
<p>All samples need to be unpacked prior to execution extraction attempts.</p>
<p>Our extractor takes either a directory of samples with <strong>-d</strong> option or <strong>-f</strong> for a single sample and then can output parts of the configuration of note, specifically:</p>
<ul>
<li><strong>-k</strong> : extract the encryption keys</li>
<li><strong>-c</strong> : extract the C2 information</li>
<li><strong>-s</strong> : extract the wide-character strings</li>
<li><strong>-a</strong> : extract the ASCII character strings</li>
</ul>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data netwire_loader_config_extractor:latest -d &quot;C:\tmp\samples&quot;
</code></pre>
<p><img src="https://www.elastic.co/security-labs/assets/images/netwire-configuration-extractor/image6.jpg" alt="NETWIRE configuration extractor" /></p>
<p>You can collect the extracted configurations from the directory you set when running the extractor.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/security-labs/assets/images/netwire-configuration-extractor/tools-image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[BLISTER Configuration Extractor]]></title>
            <link>https://www.elastic.co/security-labs/blister-configuration-extractor</link>
            <guid>blister-configuration-extractor</guid>
            <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Python script to extract the configuration and payload from BLISTER samples.]]></description>
            <content:encoded><![CDATA[<p>Python script to extract the configuration and payload from BLISTER samples.</p>
<p><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blt9bce8a0e1a513bd5/62882db13b9b8554904a4baa/blister-config-extractor.tar.gz">Download blister-config-extractor.tar.gz</a></p>
<h2>Getting Started</h2>
<p>This tool provides a Python module and command line tool that will extract configurations from the BLISTER malware loader and dump the results to screen.</p>
<blockquote>
<p>For information on the BLISTER malware loader and campaign observations, check out our blog posts detailing this:</p>
<ul>
<li><a href="https://www.elastic.co/security-labs/elastic-security-uncovers-blister-malware-campaign">BLISTER Campaign Analysis</a></li>
<li><a href="https://www.elastic.co/security-labs/blister-loader">BLISTER Malware Analysis</a></li>
</ul>
</blockquote>
<h3>Docker</h3>
<p>We can easily run the extractor with Docker, first we need to build the image:</p>
<pre><code>docker build . -t blister-config-extractor
</code></pre>
<p>Then we run the container with the <strong>-v</strong> flag to map a host directory to the docker container directory:</p>
<pre><code>docker run -ti --rm -v \
&quot;$(pwd)/binaries&quot;:/binaries blister-config-extractor:latest -d /binaries/

</code></pre>
<p>We can either specify a single sample with <strong>-f</strong> option or a directory of samples with <strong>-d</strong>.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/blister-configuration-extractor/blister-configuration-extractor-image41.jpg" alt="BLISTER configuration extrator output" /></p>
<h3>Running it Locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
blister-config-extractor -h

</code></pre>
<p>Once that works, you can do the same sort of things as mentioned in the Docker instructions above.</p>
<h2>References</h2>
<ul>
<li>Customised Rabbit cipher implementation based on <a href="https://github.com/Robin-Pwner/Rabbit-Cipher/">Rabbit-Cipher</a></li>
</ul>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/security-labs/assets/images/blister-configuration-extractor/tools-image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[BPFDoor Configuration Extractor]]></title>
            <link>https://www.elastic.co/security-labs/bpfdoor-configuration-extractor</link>
            <guid>bpfdoor-configuration-extractor</guid>
            <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Configuration extractor to dump out hardcoded passwords with BPFDoor.]]></description>
            <content:encoded><![CDATA[<p>Configuration extractor to dump out hardcoded passwords with BPFDoor.</p>
<p><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blt3f57100ade3473c5/62882ccdb4fa6b61ed70ba87/bpfdoor-config-extractor.tar.gz">Download bpfdoor-config-extractor.tar.gz</a></p>
<h2>Overview</h2>
<p>This tool provides a Python module and command line tool that will extract passwords from BPFDoor samples.</p>
<blockquote>
<p>The Elastic Security Team has released an indepth analysis of the BPFDoor malware and created an additional tool that will scan for BPFDoor infected hosts.</p>
<ul>
<li><a href="https://bookish-bassoon-c37be003.pages.github.io/intelligence/2022/05/04.bpfdoor/article/">BPFDoor analysis</a></li>
<li><a href="https://www.elastic.co/security-labs/bpfdoor-scanner">BPFDoor scanner</a></li>
</ul>
</blockquote>
<h2>Getting Started</h2>
<h3>Docker</h3>
<p>We can easily run the extractor with Docker, first we need to build the image.</p>
<pre><code>Building the BPFDoor Docker image

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

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

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

Author: Elastic Security (MARE)

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


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

options:
  -h, --help            show this help message and exit
  -f FILENAME, --file FILENAME
                        File
  -d DIRNAME, --dir DIRNAME
                        Directory

</code></pre>
<h3>Running it Locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
bpfdoor-extractor --help
</code></pre>
<p>Once that works, you can do the same sort of things as mentioned in the Docker instructions above.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/security-labs/assets/images/bpfdoor-configuration-extractor/tools-image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[BPFDoor Scanner]]></title>
            <link>https://www.elastic.co/security-labs/bpfdoor-scanner</link>
            <guid>bpfdoor-scanner</guid>
            <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Python script to identify hosts infected with the BPFDoor malware.]]></description>
            <content:encoded><![CDATA[<p>Python script to identify hosts infected with the BPFDoor malware.</p>
<p><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltae9bafece9048014/62882b50dcc93261eccb04e2/bpfdoor-scanner.tar.gz">Download bpfdoor-scanner.tar.gz</a></p>
<h2>Getting Started</h2>
<p>This tool provides a Python script to identify hosts that are infected with the BPFDoor malware.</p>
<blockquote>
<p>The Elastic Security Team has released an indepth analysis of the BPFDoor malware and created an additional tool that will extract configurations from BPFDoor malware samples.</p>
<ul>
<li><a href="https://bookish-bassoon-c37be003.pages.github.io/intelligence/2022/05/04.bpfdoor/article/">BPFDoor analysis</a></li>
<li><a href="https://www.elastic.co/security-labs/bpfdoor-configuration-extractor">BPFDoor configuration extractor</a></li>
</ul>
</blockquote>
<h3>Permissions</h3>
<p>On Linux (and thus in a container), the tool requires the following permissions:</p>
<ul>
<li>CAP_NET_BIND_SERVICE</li>
<li>CAP_NET_RAW</li>
</ul>
<p>On any *NIX host, running the script with sudo will get you what you need. As long as you don’t strip the privileges listed for your container and you publish the UDP port you intend to receive on, you should be set.</p>
<h3>Docker</h3>
<p>We can easily run the scanner with Docker, first we need to build the image:</p>
<pre><code>Building the BPFDoor scanner Docker image

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

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

Usage: bpfdoor-scanner [OPTIONS]

  Sends a discovery packet to suspected BPFDoor endpoints.

  Example usage:

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

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

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

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

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

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

## Default output will use localhost:9092, see reference config
output.elasticsearch:
  enabled: True
  username: elastic
  password: &lt;PASSWORD&gt;

</code></pre>
<p>Now, run the container, passing in our local configuration. The -v flag here will add informational messages to the log output. Here, it tells us how many documents were successfully parsed and written.</p>
<pre><code>docker run -ti --rm -v &quot;$(pwd)/config.local.yml:/config.yml&quot; \
    cobalt-strike-extractor:latest -c /config.yml -v

</code></pre>
<p><em>Output</em>:</p>
<pre><code>[2022-01-10T21:33:31.493][INFO] Setting up input/output
[2022-01-10T21:33:31.493][INFO] Connecting to Elasticsearch for input
[2022-01-10T21:33:31.493][INFO] Successfully connected to Elasticsearch for input
[2022-01-10T21:33:31.834][INFO] Connecting to Elasticsearch for output
[2022-01-10T21:33:31.835][INFO] Successfully connected to Elasticsearch for output
[2022-01-10T21:33:33.030][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.078][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.093][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.096][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.097][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.097][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.097][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.098][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.186][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.191][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.461][WARNING] Could not parse source as PE file (DOS Header magic not found.)
[2022-01-10T21:33:33.516][WARNING] CobaltStrike Beacon config not found:
[2022-01-10T21:33:33.927][INFO] Wrote 2 docs to Elasticsearch

</code></pre>
<p>The [WARNING] messages here are to be expected. These are simply source documents that didn’t contain the configuration information.</p>
<h4>Filter by time</h4>
<p>To limit the search by time frame, you can add the --since argument, which takes either an ISO-formatted date time string or you can use <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html#ranges-on-dates">Elastic date math</a>. For example, to limit search to the last 30 days, you can do the following.</p>
<pre><code>docker run -ti --rm -v &quot;$(pwd)/config.local.yml:/config.yml&quot; \
    cobalt-strike-extractor:latest --since &quot;now-30d/d&quot; -c config.local.yml

</code></pre>
<h4>Pipe output to other tools</h4>
<p>Lastly, you can pipe the output to other commands, such as jq to do local analysis. You can also override the configuration file values using environment variables.</p>
<pre><code>docker run -i --rm -a stdin -a stdout -a stderr \
    -v &quot;$(pwd)/config.local.yml:/config.yml&quot; \
    -e &quot;OUTPUT_ELASTICSEARCH_ENABLED=False&quot; \
    -e &quot;OUTPUT_CONSOLE_ENABLED=True&quot; cobalt-strike-extractor:latest -c /config.yml -q | jq  '.cobaltstrike.server.hostname'

</code></pre>
<p>In the example above, we disabled the Elasticsearch output and enabled the Console output using environment variables. We made the output more quiet using the -q flag (hiding the warnings). Then, we used jq to just pull out the “hostname” value of the configuration.</p>
<h3>Running it Locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
cobalt-strike-extractor --help

</code></pre>
<p>Once that works, you can do the same sort of things as mentioned in the Docker instructions above.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/security-labs/assets/images/cobalt-strike-beacon-extractor/tools-image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[EMOTET Configuration Extractor]]></title>
            <link>https://www.elastic.co/security-labs/emotet-configuration-extractor</link>
            <guid>emotet-configuration-extractor</guid>
            <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Python script to extract the configuration from EMOTET samples.]]></description>
            <content:encoded><![CDATA[<p>Python script to extract the payload from EMOTET samples.</p>
<p><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blte2addf7080c31792/635ad4a5a739cc5f6cbd595e/emotet-configuration-extractor.tar.gz">Download emotet-configuration-extractor.tar.gz</a></p>
<blockquote>
<p>For information on the EMOTET malware check out the following resources:</p>
<ul>
<li><a href="https://www.elastic.co/security-labs/emotet-dynamic-configuration-extraction">EMOTET Dynamic Configuration Extraction</a></li>
</ul>
</blockquote>
<h2>Getting started</h2>
<h3>Docker</h3>
<p>The recommended and easiest way to get going is to use Docker. From the directory this README is in, you can build a local container.</p>
<pre><code>docker build . -t emotet-config-extractor
</code></pre>
<p>Then we run the container with the <strong>-v</strong> flag to map a host directory to the docker container directory.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data emotet-config-extractor:latest --help
</code></pre>
<h3>Running it locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
emotet-config-extractor --help
</code></pre>
<h2>Usage</h2>
<p>All samples need to be unpacked prior to execution extraction attempts.</p>
<p>Our extractor takes either a directory of samples with <strong>-d</strong> option or <strong>-f</strong> for a single sample and then can output parts of the configuration of note, specifically:</p>
<ul>
<li><strong>-k</strong> : extract the encryption keys</li>
<li><strong>-c</strong> : extract the C2 information</li>
<li><strong>-s</strong> : extract the wide-character strings</li>
<li><strong>-a</strong> : extract the ASCII character strings</li>
</ul>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data emotet-config-extractor:latest -d &quot;C:\tmp\samples&quot;
</code></pre>
<p><img src="https://www.elastic.co/security-labs/assets/images/emotet-configuration-extractor/image.jpg" alt="EMOTET configuration extractor" /></p>
<p>You can collect the extracted configurations from the directory you set when running the extractor.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/security-labs/assets/images/emotet-configuration-extractor/tools-image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[ICEDID Configuration Extractor]]></title>
            <link>https://www.elastic.co/security-labs/icedid-configuration-extractor</link>
            <guid>icedid-configuration-extractor</guid>
            <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Python script to extract the configuration from ICEDID samples.]]></description>
            <content:encoded><![CDATA[<p>Python script to extract the payload from ICEDID samples.</p>
<p><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blt95ce19ae8cffda29/6351abcf20f42038fb989fae/icedid-config-extractor.tar.gz">Download icedid-configuration-extractor.tar.gz</a></p>
<blockquote>
<p>For information on the ICEDID malware and network infrastructure, check out the following resources:</p>
<ul>
<li><a href="https://www.elastic.co/security-labs/icedids-network-infrastructure-is-alive-and-well">ICEDIDs network infrastructure is alive and well</a></li>
<li><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltb86bffd1aef20c5b/6351aba34e565f1cdce29da5/icedid-checker.tar.gz">ICEDID network infrastructure checking utility</a></li>
</ul>
</blockquote>
<h2>Getting started</h2>
<h3>Docker</h3>
<p>The recommended and easiest way to get going is to use Docker. From the directory this README is in, you can build a local container.</p>
<pre><code>docker build . -t icedid_loader_config_extractor
</code></pre>
<p>Then we run the container with the -v flag to map a host directory to the docker container directory.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data icedid_loader_config_extractor:latest --help
</code></pre>
<h3>Running it locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
poetry lock
poetry install
poetry shell
icedid_loader_config_extractor --help
</code></pre>
<h2>Usage</h2>
<p>All samples need to be unpacked prior to execution extraction attempts.</p>
<p>We can either specify a single sample with <strong>-f</strong> option or a directory of samples with <strong>-d</strong>.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data icedid_loader_config_extractor:latest -d &quot;C:\tmp\samples&quot;
</code></pre>
<p><img src="https://www.elastic.co/security-labs/assets/images/icedid-configuration-extractor/196841115-5a3a0d95-8df4-45c2-9baa-264cfa9530e9.jpg" alt="ICEDID configuration extractor" /></p>
<p>You can collect the extracted configurations from the directory you set when running the extractor.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/security-labs/assets/images/icedid-configuration-extractor/tools-image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[PARALLAX Payload Extractor]]></title>
            <link>https://www.elastic.co/security-labs/parallax-payload-extractor</link>
            <guid>parallax-payload-extractor</guid>
            <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Python script to extract the payload from PARALLAX samples.]]></description>
            <content:encoded><![CDATA[<p>Python script to extract the payload from PARALLAX samples.</p>
<p><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltdcec03c5c91923f5/633613d524bebb2394c2773d/parallax-payload-extractor.tar.gz">Download parallax-payload-extractor.tar.gz</a></p>
<blockquote>
<p>For information on the PARALLAX malware loader and campaign observations, check out our <a href="https://elastic.co/security-labs/exploring-the-ref2731-intrusion-set">blog posts</a> detailing this intrusion set.</p>
</blockquote>
<h2>Getting started</h2>
<h3>Docker</h3>
<p>The recommended and easiest way to get going is to use Docker. From the directory this README is in, you can build a local container.</p>
<pre><code>docker build . -t parallax_loader_payload_extractor
</code></pre>
<p>Then we run the container with the -v flag to map a host directory to the docker container directory.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data parallax_loader_payload_extractor:latest --help
</code></pre>
<h3>Running it locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
parallax_loader_payload_extractor --help
</code></pre>
<h2>Usage</h2>
<p>We can either specify a single sample with <strong>-f</strong> option or a directory of samples with <strong>-d</strong>. You can use the -o switch to set the output directory of the payloads.</p>
<pre><code>docker run -ti --rm -v $(pwd)/data:/data parallax_loader_payload_extractor:latest -d /data -o /data
</code></pre>
<p><img src="https://www.elastic.co/security-labs/assets/images/parallax-payload-extractor/image41.jpg" alt="PARALLAX payload extractor" /></p>
<p>You can collect the extracted payloads from the directory you set when running the extractor, the data directory in the root of the extractor in the above example.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/security-labs/assets/images/parallax-payload-extractor/tools-image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[QBOT Configuration Extractor]]></title>
            <link>https://www.elastic.co/security-labs/qbot-configuration-extractor</link>
            <guid>qbot-configuration-extractor</guid>
            <pubDate>Tue, 06 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Python script to extract the configuration from QBOT samples.]]></description>
            <content:encoded><![CDATA[<p>Python script to extract the configuration from QBOT samples.</p>
<p><a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blta4523f3b586ba6ac/62e16e26d2f5267009ac073a/qbot-config-extractor.tar.gz">Download qbot-config-extractor.tar.gz</a></p>
<h2>Getting Started</h2>
<p>This tool provides a Python module and command line tool that will extract configurations from the QBOT malware samples and dump the results to screen.</p>
<blockquote>
<p>For information on the QBOT attack pattern and malware analysis, check out our blog posts detailing this:</p>
<ul>
<li><a href="https://www.elastic.co/security-labs/exploring-the-qbot-attack-pattern">Exploring the QBOT Attack Pattern</a></li>
<li><a href="https://www.elastic.co/security-labs/qbot-malware-analysis">QBOT Malware Analysis</a></li>
</ul>
</blockquote>
<h3>Docker</h3>
<p>We can easily run the extractor with Docker, first we need to build the image:</p>
<pre><code>docker build . -t qbot-config-extractor
</code></pre>
<p>Then we run the container with the <strong>-v</strong> flag to map a host directory to the docker container directory:</p>
<pre><code>docker run -ti --rm -v \
&quot;$(pwd)/data&quot;:/data qbot-config-extractor:latest -d /data/
</code></pre>
<p>We can either specify a single sample with <strong>-f</strong> option or a directory of samples with <strong>-d</strong>.</p>
<pre><code>$ docker run -ti --rm -v $(pwd)/data:/data qbot-config-extractor:latest -f data/c2ba065654f13612ae63bca7f972ea91c6fe97291caeaaa3a28a180fb1912b3a

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

...truncated...

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

...truncated...
</code></pre>
<h3>Running it Locally</h3>
<p>As mentioned above, Docker is the recommended approach to running this project, however you can also run this locally. This project uses <a href="https://python-poetry.org/">Poetry</a> to manage dependencies, testing, and metadata. If you have Poetry installed already, from this directory, you can simply run the following commands to run the tool. This will setup a virtual environment, install the dependencies, activate the virtual environment, and run the console script.</p>
<pre><code>poetry lock
poetry install
poetry shell
qbot-config-extractor -h
</code></pre>
<p>Once that works, you can do the same sort of things as mentioned in the Docker instructions above.</p>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/security-labs/assets/images/qbot-configuration-extractor/tools-image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[EMOTET Dynamic Configuration Extraction]]></title>
            <link>https://www.elastic.co/security-labs/emotet-dynamic-configuration-extraction</link>
            <guid>emotet-dynamic-configuration-extraction</guid>
            <pubDate>Thu, 01 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic Security Labs discusses the EMOTET trojan and is releasing a tool to dynamically extract configuration files using code emulators.]]></description>
            <content:encoded><![CDATA[<h2>Key takeaways</h2>
<ul>
<li>The EMOTET developers have changed the way they encode their configuration in the 64bit version of the malware.</li>
<li>Using code emulation we can bypass multiple code obfuscation techniques.</li>
<li>The use of code emulators in config extractors will become more prevalent in the future.</li>
</ul>
<blockquote>
<p>To download the EMOTET configuration extractor, check out our post on the tool:</p>
<ul>
<li><a href="https://www.elastic.co/security-labs/emotet-configuration-extractor">EMOTET configuration extractor</a></li>
</ul>
</blockquote>
<h2>Preamble</h2>
<p>The <a href="https://malpedia.caad.fkie.fraunhofer.de/details/win.emotet">EMOTET</a> family broke onto the malware scene as a <a href="https://web.archive.org/web/20140701001622/https://blog.trendmicro.com/trendlabs-security-intelligence/new-banking-malware-uses-network-sniffing-for-data-theft/">modular banking trojan in 2014</a>, focused on harvesting and exfiltrating bank account information by inspecting traffic. EMOTET has been adapted as an early-stage implant used to load other malware families, such as <a href="https://www.elastic.co/security-labs/exploring-the-qbot-attack-pattern">QAKBOT</a>, <a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_Trickbot.yar">TRICKBOT</a>, and <a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Ransomware_Ryuk.yar">RYUK</a>. While multiple EMOTET campaigns have been dismantled by international law enforcement entities, it has continued to operate as one of the most prolific cybercrime operations.</p>
<p>For the last several months, Elastic Security has observed the EMOTET developers <a href="https://twitter.com/Cryptolaemus1/status/1516261512372965383?ref_src=twsrc%5Etfw">transition</a> to a 64-bit version of their malware. While this change does not seem to impact the core functionality of the samples we have witnessed, we did notice a change in how the configuration and strings are obfuscated. In earlier versions of EMOTET, the configuration was stored in an encrypted form in the <strong>.data</strong> section of the binary. In the newer versions the configuration is calculated at runtime. The information we need to extract the configuration from the binary is thus hidden within the actual code.</p>
<p>In the next sections, we’ll discuss the following as it relates to 64-bit EMOTET samples:</p>
<ul>
<li>EMOTET encryption mechanisms</li>
<li>Reviewing the EMOTET C2 list</li>
<li>Interesting EMOTET strings</li>
<li>The EMOTET configuration extractor utility</li>
</ul>
<h2>Encryption keys</h2>
<p>EMOTET uses embedded <a href="https://blog.cloudflare.com/a-relatively-easy-to-understand-primer-on-elliptic-curve-cryptography/">Elliptic Curve Cryptography</a> (ECC) public keys to encrypt their network communication. While in previous versions, the keys would be stored in an XOR-encrypted blob, now the content is calculated at runtime.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/emotet-dynamic-configuration-extraction/image14.jpg" alt="Encoded Encryption Key blob in 64-bit version" /></p>
<p>In comparison the previous versions of EMOTET would store an encrypted version of the key data in the . <strong>text</strong> section of the binary.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/emotet-dynamic-configuration-extraction/image10.jpg" alt="Embedded key data in previous version of the malware" /></p>
<p>In order to make it harder for security researchers to find the given code the malware uses <a href="https://www.usenix.org/conference/usenixsecurity21/presentation/liu-binbin">Mixed Boolean-Arithmetic</a> (MBA) as one of its obfuscation techniques. It transforms constants and simple expressions into expressions that contain a mix of Boolean and arithmetic operations.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/emotet-dynamic-configuration-extraction/image6.jpg" alt="Example of Mixed Boolean-Arithmetic" /></p>
<p>In this example, an array of constants is instantiated, but looking at the assembly we see that every constant is calculated at runtime. This method makes it challenging to develop a signature to target this function.</p>
<p>We noticed that both the <a href="https://cryptobook.nakov.com/asymmetric-key-ciphers/ecdh-key-exchange">Elliptic Curve Diffie-Hellman</a> (ECDH) and <a href="https://cryptobook.nakov.com/digital-signatures/ecdsa-sign-verify-messages">Elliptic Curve Digital Signature Algorithm</a> (ECDSA) keys use the same function to decode the contents.</p>
<p>The ECDH key (which you can recognize by its magic ECK1 bytes) is used for encryption purposes while the ECDSA key (ECC1) is used for verifying the C2 server's responses.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/emotet-dynamic-configuration-extraction/image4.jpg" alt="ECK1 magic bytes at the start of the key data" /></p>
<p><img src="https://www.elastic.co/security-labs/assets/images/emotet-dynamic-configuration-extraction/image11.jpg" alt="Decoding algorithm for the key material" /></p>
<p>By leveraging a YARA signature to find the location of this decode function within the EMOTET binary we can observe the following process:</p>
<ol>
<li>Find the decoding algorithm within the binary.</li>
<li>Locate any Cross References (<a href="https://hex-rays.com/blog/igor-tip-of-the-week-16-cross-references/">Xrefs</a>) to the decoding function.</li>
<li>Emulate the function that calls the decoding function.</li>
<li>Read the resulting data from memory.</li>
</ol>
<p>As we mentioned, we first find the function in the binary by using YARA. The signature is provided at the <a href="https://www.elastic.co/security-labs/emotet-dynamic-configuration-extraction#yara">end of this article</a>. It is worth pointing out that these yara signatures are used to identify locations in the binary but are, in their current form, not usable to identify EMOTET samples.</p>
<p>In order to automatically retrieve the data from multiple samples, we created a configuration extractor. In the snippets below, we will demonstrate, in a high level fashion, how we collect the configuration information from the malware samples.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/emotet-dynamic-configuration-extraction/image7.jpg" alt="Python code to find the start of a function" /></p>
<p>In the above code snippet:</p>
<ol>
<li>First load the YARA signature.</li>
<li>Try to find a match, and if a signature is found in the file.</li>
<li>Calculate the function offset based on the offset in the file.</li>
</ol>
<p>In order to locate the Xrefs to this function, we use the excellent <a href="https://github.com/danielplohmann/smda">SMDA decompiler</a>. After locating the Xrefs, we can start the emulation process using the CPU emulator, <a href="https://www.unicorn-engine.org/">Unicorn</a>.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/emotet-dynamic-configuration-extraction/image8.jpg" alt="Python code used to emulate decoding functions" /></p>
<ol>
<li>Initialize the Unicorn emulator.</li>
<li>Load the executable code from the PE file into memory.</li>
<li>Disassemble the function to find the return and the end of the execution.</li>
<li>The binary will try to use the windows <a href="https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc">HeapAlloc API</a> to allocate space for the decoded data. Since we don't want to emulate any windows API's, as this would add unnecessary complexity, we hook to code so that we can allocate space ourselves.</li>
<li>After the emulation has run the 64-bit “long size” register (<a href="https://www.cs.uaf.edu/2017/fall/cs301/lecture/09_11_registers.html#:~:text=rax%20is%20the%2064%2Dbit,processors%20with%20the%2080386%20CPU.">RAX</a>), it will contain a pointer to the key data in memory.</li>
<li>To present the key in a more readable way, we convert it to the standard PEM format.</li>
</ol>
<p>By emulating the parts of the binary that we are interested in, we no longer have to statically defeat the obfuscation in order to retrieve the hidden contents. This approach adds a level of complexity to the creation of config extractors. However, since malware authors are adding ever more obfuscation, there is a need for a generic approach to defeating these techniques.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/emotet-dynamic-configuration-extraction/image3.jpg" alt="Example of the extractor used to find key material" /></p>
<h2>C2 server list</h2>
<p>An important part of tracking malware families is to get new insights by identifying and discovering which C2 servers they use to operate their network.</p>
<p>In the 64-bit versions of EMOTET, we see that the IP and port information of the C2 servers are also dynamically calculated at runtime. Every C2 server is represented by a function that calculates and returns a value for the IP address and the port number.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/emotet-dynamic-configuration-extraction/image13.jpg" alt="Examples of encoded IP/port combination" /></p>
<p>These functions don’t have a direct cross reference available for searching. However, a procedure references all the C2 functions and creates the <strong>p_c2_list</strong> array of pointers.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/emotet-dynamic-configuration-extraction/image1.jpg" alt="C2 server list" /></p>
<p>After that, we can emulate every C2-server function individually to retrieve the IP and port combination as seen below.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/emotet-dynamic-configuration-extraction/image9.jpg" alt="Example of the extractor used to find C2 server list" /></p>
<h2>Strings</h2>
<p>The same method is applied to the use of strings in memory. Every string has its own function. In the following example, the function would return a pointer to the string <strong>%s\regsvr32.exe &quot;%s&quot;</strong>.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/emotet-dynamic-configuration-extraction/image15.jpg" alt="Encoded string" /></p>
<p>All of the EMOTET strings share a common function to decode or resolve the string at runtime. In the sample that we are analyzing here, the string resolver function is referenced 29 times.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/emotet-dynamic-configuration-extraction/image2.jpg" alt="String decoding algorithm" /></p>
<p>This allows us to follow the same approach as noted earlier in order to decode all of the EMOTET strings. We pinpoint the string decoding function using YARA, find the cross-references, and emulate the resulting functions.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/emotet-dynamic-configuration-extraction/image12.jpg" alt="Example of the extractor used to find strings" /></p>
<h2>Configuration extractor</h2>
<p>Automating the payload extraction from EMOTET is a crucial aspect of threat hunting as it gives visibility of the campaign and the malware deployed by the threat actors, enabling practitioners to discover new unknown samples in a timely manner.</p>
<pre><code>% emotet-config-extractor --help
usage: Emotet Configuration Extractor [-h] (-f FILE | -d DIRECTORY) [-k] [-c] [-s] [-a]

options:
  -h, --help            show this help message and exit
  -f FILE, --file FILE  Emotet sample path
  -d DIRECTORY, --directory DIRECTORY
                        Emotet samples folder
  -k                    Extract Encryption keys
  -c                    Extract C2 information
  -s                    Extract strings
  -a                    Extract strings (ascii)
</code></pre>
<p>Our extractor takes either a directory of samples with <strong>-d</strong> option or <strong>-f</strong> for a single sample and then can output parts of the configuration of note, specifically:</p>
<ul>
<li><strong>-k</strong> : extract the encryption keys</li>
<li><strong>-c</strong> : extract the C2 information</li>
<li><strong>-s</strong> : extract the wide-character strings</li>
<li><strong>-a</strong> : extract the ASCII character stings</li>
</ul>
<p>EMOTET uses a different routine for decoding wide and ASCII strings. That is why the extractor provides flags to extract them separately.</p>
<p>The C2 information displays a list of IP addresses found in the sample. It is worth noting that EMOTET downloads submodules to perform specific tasks. These submodules can contain their own list of C2 servers. The extractor is also able to process these submodules.</p>
<p>The submodules that we observed do not contain encryption keys. While processing submodules you can omit the <strong>-k</strong> flag.</p>
<pre><code>[...]
[+] Key type: ECK1
[+] Key length: 32
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2DWT12OLUMXfzeFp+bE2AJubVDsW
NqJdRC6yODDYRzYuuNL0i2rI2Ex6RUQaBvqPOL7a+wCWnIQszh42gCRQlg==
-----END PUBLIC KEY-----
[...]
[+] Key type: ECS1
[+] Key length: 32
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9C8agzYaJ1GMJPLKqOyFrlJZUXVI
lAZwAnOq6JrEKHtWCQ+8CHuAIXqmKH6WRbnDw1wmdM/YvqKFH36nqC2VNA==
-----END PUBLIC KEY-----
[...]
[+] Found 64 c2 subs
174.138.33.49:7080
188.165.79.151:443
196.44.98.190:8080
[...]
[+] Starting emulation
[+] String BLOB address: 0x4000000
KeyDataBlob
[...]
[+] String BLOB address: 0x4000000
bcrypt.dll
[...]
[+] String BLOB address: 0x4000000
RNG
</code></pre>
<p>To enable the community to further defend themselves against existing and new variants of EMOTET, we are making the payload extractor open source under the Apache 2 License. Access the <a href="https://www.elastic.co/security-labs/emotet-configuration-extractor">payload extractor documentation and binary download</a>.</p>
<h2>The future of EMOTET</h2>
<p>The EMOTET developers are implementing new techniques to hide their configurations from security researchers. These techniques will slow down initial analysis, however, EMOTET will eventually have to execute to achieve its purpose, and that means that we can collect information that we can use to uncover more about the campaign and infrastructure. Using code emulators, we can still find and extract the information from the binary without having to deal with any obfuscation techniques. EMOTET is a great example where multiple obfuscation techniques make static analysis harder. But of course, we expect more malware authors to follow the same example. That is why we expect to see more emulation-based configuration extract in the future.</p>
<p><img src="https://www.elastic.co/security-labs/assets/images/emotet-dynamic-configuration-extraction/image5.png" alt="EMOTET running and gathering system information" /></p>
<h2>Detection</h2>
<h3>YARA</h3>
<p>Elastic Security has created YARA rules to identify this activity. The YARA rules shown here are not meant to be used to solely detect EMOTET binaries, they are created to support the configuration extractor. The YARA rules for detecting EMOTET can be found in the <a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_Emotet.yar">protections-artifacts repository</a>.</p>
<h4>EMOTET key decryption function</h4>
<pre><code>rule resolve_keys
{
meta:
     author = &quot;Elastic Security&quot;
     description = &quot;EMOTET - find the key decoding algorithm in the PE&quot;
     creation_date = &quot;2022-08-02&quot;
     last_modified = &quot;2022-08-11&quot;
     os = &quot;Windows&quot;
     family = &quot;EMOTET&quot;
     threat_name = &quot;Windows.Trojan.EMOTET&quot;
     reference_sample = &quot;debad0131060d5dd9c4642bd6aed186c4a57b46b0f4c69f1af16b1ff9c0a77b1&quot;
   strings:
       $chunk_1 = {
        45 33 C9
        4C 8B D0
        48 85 C0
        74 ??
        48 8D ?? ??
        4C 8B ??
        48 8B ??
        48 2B ??
        48 83 ?? ??
        48 C1 ?? ??
        48 3B ??
        49 0F 47 ??
        48 85 ??
        74 ??
        48 2B D8
        42 8B 04 03
     }
   condition:
       any of them
}
</code></pre>
<h4>EMOTET C2 aggregation</h4>
<pre><code>rule c2_list
{
     author = &quot;Elastic Security&quot;
     description = &quot;EMOTET - find the C2 collection in the PE&quot;
     creation_date = &quot;2022-08-02&quot;
     last_modified = &quot;2022-08-11&quot;
     os = &quot;Windows&quot;
     family = &quot;EMOTET&quot;
     threat_name = &quot;Windows.Trojan.EMOTET&quot;
     reference_sample = &quot;debad0131060d5dd9c4642bd6aed186c4a57b46b0f4c69f1af16b1ff9c0a77b1&quot;
  strings:
     $chunk_1 = {
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
        48 8D 05 ?? ?? ?? ??
        48 89 81 ?? ?? ?? ??
     }
  condition:
     any of them
}
</code></pre>
<h4>EMOTET string decoder</h4>
<pre><code>rule string_decode
{
   meta:
     author = &quot;Elastic Security&quot;
     description = &quot;EMOTET - find the string decoding algorithm in the PE&quot;
     creation_date = &quot;2022-08-02&quot;
     last_modified = &quot;2022-08-11&quot;
     os = &quot;Windows&quot;
     family = &quot;EMOTET&quot;
     threat_name = &quot;Windows.Trojan.EMOTET&quot;
     reference_sample = &quot;debad0131060d5dd9c4642bd6aed186c4a57b46b0f4c69f1af16b1ff9c0a77b1&quot;
  strings:
     $chunk_1 = {
        8B 0B
        49 FF C3
        48 8D 5B ??
        33 CD
        0F B6 C1
        66 41 89 00
        0F B7 C1
        C1 E9 10
        66 C1 E8 08
        4D 8D 40 ??
        66 41 89 40 ??
        0F B6 C1
        66 C1 E9 08
        66 41 89 40 ??
        66 41 89 48 ??
        4D 3B D9
        72 ??
     }
     $chunk_2 = {
        8B 0B
        49 FF C3
        48 8D 5B ??
        33 CD
        0F B6 C1
        66 41 89 00
        0F B7 C1
        C1 E9 ??
        66 C1 E8 ??
        4D 8D 40 ??
        66 41 89 40 ??
        0F B6 C1
        66 C1 E9 ??
        66 41 89 40 ??
        66 41 89 48 ??
        4D 3B D9
        72 ??
     }
  condition:
     any of them
}
</code></pre>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/security-labs/assets/images/emotet-dynamic-configuration-extraction/lock-code-combination-configuration.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Extracting Cobalt Strike Beacon Configurations]]></title>
            <link>https://www.elastic.co/security-labs/extracting-cobalt-strike-beacon-configurations</link>
            <guid>extracting-cobalt-strike-beacon-configurations</guid>
            <pubDate>Fri, 09 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Part 2 - Extracting configurations from Cobalt Strike implant beacons.]]></description>
            <content:encoded><![CDATA[<p>Please check out our <a href="https://www.elastic.co/security-labs/collecting-cobalt-strike-beacons-with-the-elastic-stack">previous post</a> on how to collect Cobalt Strike beacon implants. We'll build on that information to extract the configurations from the beacons.</p>
<p>In this post, we'll walk through manually analyzing a Cobalt Strike C2 configuration from a binary beacon payload using the excellent <a href="https://github.com/strozfriedberg/cobaltstrike-config-extractor">Cobalt Strike Configuration Extractor (CSCE)</a>. We'll also cover enabling some newer features of the Elastic Stack that will allow you to do this at scale across all your monitored endpoints, by extracting the beacons from memory.</p>
<blockquote>
<p>The team at Blackberry has a tremendous handbook called “<a href="https://www.blackberry.com/us/en/forms/enterprise/ebook-beacons-in-the-dark">Finding Beacons in the Dark</a>” (registration required) that dives extensively into Cobalt Strike beacon configurations. We’ll discuss a few fields in the configurations here, but if you’re interested in learning about how beacons function, we strongly recommend checking that resource out.</p>
</blockquote>
<h2>Cobalt Strike Configuration Extractor</h2>
<p>The <a href="https://github.com/strozfriedberg/cobaltstrike-config-extractor">Cobalt Strike Configuration Extractor (CSCE)</a> by Stroz Friedberg is a &quot;python library and set of scripts to extract and parse configurations from Cobalt Strike beacons&quot;.</p>
<p>To use the CSCE, we'll create a Python virtual environment, activate it, and install the CSCE Python package.</p>
<h2>Setting up the Cobalt Strike Configuration Extractor</h2>
<pre><code>$ python3 -m venv csce

$ source csce/bin/activate

(csce) $ pip3 install libcsce

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

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

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