一次失败的(国家支持?)攻击剖析

Lobsters Hottest 新闻

摘要

对一次针对Rust开发者的复杂假面试骗局的详细复盘,该骗局涉及伪造的VC人设和通过TypeScript仓库投递的定制RAT。作者凭借警惕性和AI辅助代码审查成功规避了感染。

<p><a href="https://lobste.rs/s/j2ua4f/anatomy_failed_nation_state_attack">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/06/26 16:10

# 一次失败的(国家级?)攻击解剖分析 来源: https://grack.com/blog/2026/06/25/dissecting-a-failed-nation-state-attack/ **声明** 🧠 本文完全由人类撰写:除IoC信息外,所有内容均为原创。由于篇幅所限,使用Claude加速了RAT分析并构建了IoC检测脚本。因本人居住于加拿大,该信息已报告给相关加拿大机构(CCCS等)。携带Payload的图像文件在 VirusTotal (https://www.virustotal.com/gui/file/7af7864333f5d6dec2a137e2c123019dea27cae8c30b0f293b310c969635c90e/detection) 上未触发任何杀毒引擎。攻击者身份为虚构,但存在同名无关人员可能被混淆,已从本文中省略。 本周,我差点中了一个虚假面试诈骗 (https://manishearth.github.io/blog/2026/06/17/the-future-of-the-con-is-already-here/) 的圈套,该陷阱旨在入侵我的机器,从邮件上下文推断,目标可能是我的 crates.io (https://crates.io/) 上的软件包。注:根据内部字符串,我称之为“PinpinRAT”,但可能已有其他命名。网上未找到其他参考资料。 一周半前,我收到一封来自“D█████ S████”的邮件,声称来自Lua Ventures——一家当时我未知的、已倒闭的新加坡DeFi领域VC。 *需要明确:这是一个捏造的身份*,选择该名字很可能是为了容易与多名同名真人混淆。 [](https://grack.com/assets/2026/06/email1-shadow.png) 看起来像一封真实的邮件,包含一个指向略显平淡、但看起来正宗的LinkedIn个人资料的链接。 [](https://grack.com/assets/2026/06/linkedin-shadow.png) 攻击者甚至随口提到了两家正在寻求顾问工作的投资公司:Lyrasing和Roadpay。搜索这两家公司并未引起警觉——它们都有非常基础的网络存在,但没有任何迹象表明它们是假的,而非仅仅是*早期阶段*。 (roadpay.cc的archive.org快照) (https://web.archive.org/web/20260626011734/https://roadpay.cc/en)。 [](https://grack.com/assets/2026/06/email2-shadow.png) 我们来回商定会议时间,最终敲定了一个可以聊天的时段。通话本身也没有异常。一个带有德国口音、说话有点难懂的男人在电话那头。他说自己在旅行中接电话,这有点奇怪,但同样不一定是危险信号。 [](https://grack.com/assets/2026/06/email3-shadow.png) 通话后,诱饵来了。一封后续邮件提供了一份“测试”。 [](https://grack.com/assets/2026/06/email4-shadow.png) 此时我有点恼火,但并未怀疑。我克隆了仓库,但第一个真正的红旗才在这里出现。幸运的是:他们发给我的是一个TypeScript仓库。这对我来说不合逻辑。这些指示看起来更像是TypeScript面试题,而非某种架构分析。我决定将仓库压缩并丢给Claude快速扫描——出于谨慎和懒惰的双重考量。片刻之后,它识别出了一些异常: > 值得注意的是,根目录下的 package.json 没有 postinstall/preinstall hook —— 这很有趣,因为他们使用了 patch-package,而这通常需要连接到 postinstall。让我检查每个 package.json 的生命周期脚本,然后审计 patch 文件(真正的风险面——patch 可以在 node_modules 中注入任意代码)。 这引起了我的兴趣。我自己扫描了目录,注意到相当不合理的多个 `patches/` 目录。我检查的前几个看似无害,但你可能已经猜到,它们只是在制造噪音,以免真正的 payload 被发现。 ``` packages/electron-benchmarks/patches/sumchecker+3.0.1.patch packages/electron-benchmarks/patches/@electron+get+2.0.3.patch packages/electron-benchmarks/patches/extract-zip+2.0.1.patch ``` 当我还在手动慢慢检查时,Claude 识别出了 PinpinRAT 的首个迹象: > 我找到了。这是一个恶意 payload。嵌入在 `typescript+5.9.2.patch` 文件中——在看似常规的 TypeScript “模块标识符”补丁内部——一个 base64 自执行混淆存根被注入到 `_tsc.js` 和 `typescript.js` 的最顶部: > ``` > ;;(function(r,k){const d=Buffer.from(r,'base64');for(let i=0;i... > ``` > 它解码一个 base64 字符串,用密钥 73 对每个字节进行 XOR 解密,然后通过 new Function(...) 运行结果,并传入 require、process、Buffer 等。这是一个隐藏的代码执行 payload,每次运行 tsc 或任何导入 typescript.js 的东西时触发——即第一次运行 npm run typecheck / build / dev 时。 ...这就是我决定停止在自己的机器上捅马蜂窝的时刻。我用密码将其压缩,以防意外触发,然后在沙盒中继续分析。 ## 陷阱 该仓库的主题是一个名为“Ticket Harbor”的渡轮票务应用。捆绑包中包含的 `task.txt` 是一组看似合理且无聊的任务,但以以下内容结尾: > 在提交之前,运行仓库的类型检查、测试套件以及相关的桌面/服务器构建命令。 这个指令就是让你上钩的陷阱。链条如下: 1. 四个独立的 `postinstall` hook 运行 `patch-package`。但其中一个还运行了 `git update-index --skip-worktree` 对 patch 文件进行操作,这会将它们从 `git status` 中隐藏起来。 2. `typescript+5.9.2.patch` 在 `typescript.js` 和 `_tsc.js` 的顶部注入了一个自执行存根。这是一个轻度混淆的 blob,被送入 `new Function(...)`(避免 `eval`,可能是为了逃避恶意软件检测)。 3. 该加载器读取附加到名为 `operators/3.png` 的文件尾部的一个隐藏块,运行一个小的嵌入式 WASM 存根(在自定义的 `wAsm` 块中),然后生成一个分离的、静默的 Node 进程,携带一个 1.68 MB 的混淆第二级 payload。 4. 它在三个层面进行自清理:`git skip-worktree` 技巧、dropper 在首次运行后重写 `patch` 以删除自己的注入行,以及 stage-2 临时目录在执行时自删除。 *实际* payload 是一个 RAT(远程访问木马)。我原本担心这只是一个凭据窃取器,但更糟。PinpinRAT 嵌套在三个混淆层中,很难解开:obfuscator.io(声称能防御LLM,哈!),再加上两个 base64 层。 ## 它释放了什么 为了 1) 快速分享此信息和 2) 避免意外在自己机器上引爆恶意软件,我让 Claude 在它的沙盒中拆解了实际木马,并让它向我描述。需要非常明确:Claude 能够在大约5分钟内逆向工程多个级别的混淆,这比我快得多。 释放物是一个完整的远程访问木马,似乎是由一个懂行的人搭建的。它在本地设置了一个 RSA 密钥,并使用 AES-256-CBC 作为会话密钥。启动时,它会调用一个签到例程,收集并泄露主机指纹: - 主 IP 地址(枚举所有非内部接口),以及所有 IP - 用户名(`os.userInfo().username`) - 主机名 - 操作系统类型 + 发布版本 + 平台 + 架构 - 进程 PID 和完整的 `process.argv` - Node 版本 它生成一个 RSA-2048 密钥对和一个随机的 AES-256 会话密钥(aes_psk),然后所有后续流量都使用带 HMAC-SHA256 完整性标签的 AES-256-CBC 加密。支持以下命令: - `env` —— 将 process.env 通过 JSON.stringify 转储并发回。 - `upload` —— 读取任意文件路径并泄露它。 - `download` —— 将攻击者提供的字节写入任何可写路径。 - `spawn` —— 运行任意进程,可选 shell 扩展。 - `ls`/`cd`/`pwd`/`cp`/`mv` —— 通用文件系统原语。 - `dns` —— 让主机通过指定的解析器解析任意名称(用于 DNS 隧道?)。 - `dismantle` —— 自删除。 ## 危害指标 如果你运行了其中一个,应立即断开系统与网络的连接,并从另一台机器轮换你的凭据。修复*应该*直接,但请认为你的凭据(包括 cookies 和受密码保护的 secrets)已泄露。以下是 PinpinRAT 恶意软件中发现的一些危害指标: - C2: 89.124.107.161:80 - 计划任务(Windows):`PinpinWrappedJs` - 进程伪装(macOS):`com.apple.WebKit.Networking` - 环境变量:`NODT_PAYLOAD_PATH`、`NODT_PAYLOAD_ARGS` - PNG 块守卫:`WASMPACK`(wAsm) - `PINPIN_NO_AUTOSTART=1`:阻止持久化 - 包含 `mutex.js` 的 cronjob(仅当 RAT 拥有权限时,macOS 上可能不存在) - `typescript.js` 中的锚点字符串:`12ff4b51`、`ticket-harbor-tsc-shim-anchor` - 包含 payload 的 `typescript+5.9.2.patch` - 工件目录:`~/Library/Caches/runtime-cache/.cache-/`(macOS)、`/tmp/.cache-/`(Linux)、`%TEMP%\\.cache-\\`(Windows) - 包含 `payload.js` 和 `mutex.js` ## 那么,这到底是谁干的? 无法确定,但这是有针对性的,有一个相当令人信服的伪装故事、一个假身份、多个拥有被窃取历史的假网站,以及一个耐心的时间线。`git` 陷阱非常精巧。这个“虚假面试诈骗”已经成为2026年多名行动者的共同主题。真正幕后黑手是谁,现在由相关机构负责。*值得注意*的是,这针对的是像你我这样的开发者,而我正好在触发陷阱前幸运地看到了一个红旗。老实说,让我感到恐惧和清醒的是,如果这是一个 Rust 仓库,带有一个设了陷阱的 `build.rs` 脚本,我可能就已经中招了。

相似文章

AI工作空间劫持:Jscrambler NPM攻击剖析

Reddit r/artificial

攻击者劫持了Jscrambler的NPM凭证,发布了恶意版本,利用一个未记录的基于Rust的信息窃取器,从Cursor和Claude Desktop等AI工具中窃取API密钥和开发者历史记录。

关于Hugging Face事后分析的一些思考

Reddit r/AI_Agents

对OpenAI编码代理对Hugging Face发起的一次复杂网络攻击的详细分析,该攻击利用了包括Jinja库代码执行在内的多个漏洞,并凸显了向AI驱动网络安全分析的转变。

事件 CVE-2026-LGTM

Hacker News Top

一份讽刺性事件报告,详细描述了恶意软件包如何因各种故障绕过多个AI驱动的安全门,最终只有在攻击者的代理读取了本不应读取的文件后才得以解决。