
Инструмент для изучения JavaScript-вредоносного ПО.
Утилита для анализа вредоносного JavaScript.
Просто установите box-js из npm:
npm install box-js --global
box-js также доступен:
- как модуль Cuckoo (см. каталог
integrationsи Nwinternights/Cuckoo_Boxjs);- как Dockerfile (см.
integrations/README.md);- как пакет в дистрибутивах для специалистов по безопасности (REMnux, BlackArch);
- как часть приложений с открытым исходным кодом (Intel Owl);
- как часть коммерческих сторонних сервисов (any.run).
Предположим, у вас есть образец с именем sample.js: для его анализа просто выполните
box-js sample.js
Вероятно, вы также захотите загрузить полезные нагрузки; используйте флаг --download, чтобы включить загрузку. В противном случае движок будет имитировать ошибку 404, чтобы скрипт думал, что сайт распространения недоступен, и обращался к запасным сайтам.
Box.js будет эмулировать среду Windows JScript, выведет сводку эмуляции в консоль и создаст папку с именем sample.js.results (если она уже существует, будет создана sample.js.1.results и так далее). Эта папка будет содержать:
analysis.log — журнал анализа, выведенный на экран;snippets.json — список фрагментов кода, выполненных образцом (JavaScript, команды оболочки и т.д.);urls.json — список обработанных URL;active_urls.json — список URL, которые, по-видимому, загружают активное вредоносное ПО;resources.json — потоки ADODB (т.е. файлы, записанные скриптом на диск) с типами файлов и хешами;IOC.json — список поведений, идентифицированных как IOC (индикаторы компрометации). Сюда входят обращения к реестру, записанные файлы, HTTP-запросы и так далее.Вы можете проанализировать их самостоятельно или автоматически отправить на Malwr, VirusTotal или в песочницу Cuckoo: для получения дополнительной информации выполните box-export --help.
Для дополнительной изоляции рекомендуется запускать анализ во временном Docker-контейнере. См.
integrations/README.mdдля получения дополнительной информации.
Если вы хотите автоматизировать анализ, вы можете использовать коды возврата — они описаны в
integrations/README.md— чтобы различать разные типы ошибок.
Репозиторий box-js из Git включает файл boilerplate.js. Этот файл определяет некоторые заглушки распространённых браузерных объектов, таких как document. Попробуйте перезапустить анализ с опцией --prepended-code=DIR/boilerplate.js, где DIR — каталог клонированного репозитория box-js, или с --prepended-code=default. Опция --prepended-code указывает box-js добавить JavaScript из указанного файла в начало анализируемого образца.
Обратите внимание, что вы можете скопировать boilerplate.js и добавить свои собственные заглушенные классы, объекты и т.д. по мере необходимости. Используйте опцию командной строки --prepended-code=show-default, чтобы вывести полный путь к файлу boilerplate.js по умолчанию.
Хотя box.js обычно используется для отдельных файлов, он также может выполнять пакетный анализ. Вы можете просто передать список файлов или папок для анализа:
box-js sample1.js sample2.js /var/data/mySamples ...
По умолчанию box.js обрабатывает образцы параллельно, запуская по одному анализу на ядро. Вы можете использовать другой параметр, указав значение для --threads: в частности, 0 снимет ограничение, заставляя box-js запускать как можно больше потоков анализа, что приведёт к очень быстрому анализу, но может перегрузить систему (обратите внимание, что анализ обычно ограничен по CPU, а не по RAM).
Вы можете использовать --loglevel=warn, чтобы скрыть сообщения, связанные с анализом, и отображать только информацию о ходе выполнения.
После завершения анализа вы можете извлечь активные URL следующим образом:
cat ./*.results/active_urls.json | sort | uniq
NAME ОПИСАНИЕ
-h, --help Показать справку и выйти
-v, --version Показать версию пакета и выйти
--license Показать лицензию и выйти
--debug Завершить работу при ошибке эмуляции, даже в "пакетном режиме", и передать код
выхода.
--loglevel Уровень логирования (debug, verbose, info, warning, error - по умолчанию "info")
--threads При работе в пакетном режиме, сколько анализов запускать одновременно (0 =
без ограничений, по умолчанию: столько же, сколько ядер CPU)
--download Фактически загружать полезные нагрузки
--encoding Кодировка входного образца (по умолчанию будет автоматически определена)
--timeout Таймаут скрипта в секундах (по умолчанию 10)
--output-dir Расположение на диске для записи файлов и папок с результатами (по умолчанию
текущий каталог)
--preprocess Предварительная обработка исходного кода (упрощает обратную разработку, но занимает
несколько секунд)
--unsafe-preprocess Более агрессивная предварительная обработка. Часто даёт лучший код, но может сломаться на
некоторых граничных случаях (например, переопределение прототипов)
--prepended-code Входной файл или каталог, содержащий код, который должен быть добавлен в начало JS
файла(ов), который мы анализируем. Если указан каталог, добавляются содержимое всех файлов
в каталоге. Если указано 'default', используется стандартный boilerplate.js из
box-js. Если указано 'show-default', просто выводится путь к boilerplate.js
и выход (полезно, если вы хотите скопировать и изменить стандартный код boilerplate).
--fake-script-engine Движок скриптов, который будет сообщаться в WScript.FullName и WScript.Name (например,
'cscript.exe', 'wscript.exe' или 'node'). По умолчанию wscript.exe.
--fake-cl-args Поддельные аргументы командной строки скрипта. В строке они должны быть разделены
запятыми.
--fake-sample-name Поддельное имя файла для анализируемого образца. Может быть полным путём или просто
именем файла. Если в пути есть '\', экранируйте их как '\\' в значении аргумента
командной строки (например, --fake-sample-name=C:\\foo\\bar.js).
--fake-language Указать код языка для возврата Win32_OperatingSystem.OSLanguage.
Поддерживаемые значения: 'spanish', 'english' и 'portuguese'.
--fake-domain Указать домен пользователя для возврата WScript.Network.UserDomain.
--fake-download Имитировать успешные HTTP-запросы и возвращать поддельную полезную нагрузку
--no-kill Не завершать приложение при возникновении ошибок времени выполнения
--no-echo Не выводить данные, выводимые скриптом, в консоль
--no-rewrite Вообще не переписывать исходный код, кроме поддержки `@cc_on`
--no-catch-rewrite Не переписывать конструкции try..catch, чтобы сделать исключение глобальным
--no-cc_on-rewrite Не переписывать `/*@cc_on <...>@*/` в `<...>`
--no-eval-rewrite Не переписывать `eval`, чтобы его аргумент переписывался
--no-file-exists Возвращать `false` для Scripting.FileSystemObject.FileExists(x)
--limit-file-checks Переключить значение по умолчанию для проверок существования папок/файлов, если выполняется много проверок
(попытка прервать бесконечные циклы проверки файлов).
--no-folder-exists Возвращать `false` для Scripting.FileSystemObject.FileExists(x)
--function-rewrite Переписывать вызовы функций для перехвата вызовов eval
--no-rewrite-prototype Не переписывать выражения вида `function A.prototype.B()` как `A.prototype.B =
function()`
--no-hoist-prototype Не поднимать выражения вида `function A.prototype.B()` (подразумевается
no-rewrite-prototype)
--no-shell-error Не выбрасывать поддельную ошибку при выполнении `WScriptShell.Run` (по умолчанию выбрасывается поддельная
ошибка, чтобы имитировать недоступность сайтов распространения, так что
скрипт пытается опросить все сайты)
--no-typeof-rewrite Не переписывать `typeof` (например, `typeof ActiveXObject`, который должен возвращать
'unknown' по стандарту JScript, а не 'object')
--proxy [экспериментально] Использовать указанный прокси для загрузок. Это не актуально, если
флаг --download не указан.
--windows-xp Эмулировать Windows XP (влияет на значение переменных окружения)
--dangerous-vm Использовать модуль `vm`, а не `vm2`. Эта песочница может быть взломана, поэтому **не
используйте это**, если вы не уверены на 100% в том, что делаете. Помогает при отладке,
выдавая корректные стектрейсы.
--rewrite-loops Переписывать некоторые типы циклов для ускорения анализа
--throttle-writes Ограничить отчётность и отслеживание данных записи файлов, которые записывают МНОГО данных
--throttle-commands Остановить анализ, если было выполнено МНОГО одинаковых команд
--extract-conditional-code Извлечь фактический код для анализа из условных комментариев JScript (/*@if(...).
--loose-script-name Переписывать проверки == так, чтобы сравнения имени текущего скрипта с жестко заданным
именем скрипта всегда возвращали true.
--real-script-name Возвращать реальное имя файла анализируемого скрипта, а не поддельное
имя.
--activex-as-ioc Логировать все вызовы ActiveX как IOC и пытаться определить, завуалирован ли вызов
в исходном коде JS.
--ignore-wscript-quit Игнорировать вызовы WSCript.Quit() и продолжать выполнение.
--ignore-rewrite-errors Анализировать исходный образец, если не удалось переписать какой-либо образец.
Первым источником информации является вывод в консоль. При успешном анализе обычно выводится что-то вроде этого:
Using a 10 seconds timeout, pass --timeout to specify another timeout in seconds
Analyzing sample.js
Header set for http://foo.bar/baz: User-Agent Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
Emulating a GET request to http://foo.bar/baz
Downloaded 301054 bytes.
Saved sample.js.results/a0af1253-597c-4eed-9e8f-5b633ff5f66a (301054 bytes)
sample.js.results/a0af1253-597c-4eed-9e8f-5b633ff5f66a has been detected as data.
Saved sample.js.results/f8df7228-7e0a-4241-9dae-c4e1664dc5d8 (303128 bytes)
sample.js.results/f8df7228-7e0a-4241-9dae-c4e1664dc5d8 has been detected as PE32 executable (GUI) Intel 80386, for MS Windows.
http://foo.bar/baz is an active URL.
Executing sample.js.results/d241e130-346f-4c0c-a698-f925dbd68f0c in the WScript shell
Header set for http://somethingelse.com/: User-Agent Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
Emulating a GET request to http://somethingelse.com/
...
В этом случае мы видим дроппер, который загружает файл с http://foo.bar/baz, устанавливая HTTP-заголовок User-Agent в Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0). Затем он декодирует его и записывает результат на диск (исполняемый файл PE32). Наконец, он выполняет какую-то команду в оболочке Windows.
sample.js.results/a0af1253-597c-4eed-9e8f-5b633ff5f66a будет содержать полезную нагрузку, загруженную с http://foo.bar/baz;sample.js.results/f8df7228-7e0a-4241-9dae-c4e1664dc5d8 будет содержать фактическую полезную нагрузку (PE-исполняемый файл);sample.js.results/d241e130-346f-4c0c-a698-f925dbd68f0c будет содержать команду, выполненную в оболочке Windows.Каждый HTTP-запрос выводится на терминал и регистрируется в urls.json. Дублирующиеся URL не добавляются (т.е. запрос одного и того же URL дважды приведёт только к одной строке в urls.json).
active_urls.json содержит список URL, которые в итоге привели к исполняемой полезной нагрузке. Этот файл наиболее интересен, если вы хотите закрыть сайты распространения.
snippets.json содержит каждый фрагмент кода, с которым столкнулся box-js — будь то JavaScript, команда cmd.exe или скрипт PowerShell.
resources.json содержит каждый файл, записанный образцом на диск. Например, если приложение попыталось сохранить Hello world! в $PATH/foo.txt, содержимое resources.json будет:
{
"9a24...": {
"path": "(path)\\foo.txt",
"type": "ASCII text, with no line terminators",
"md5": "86fb269d190d2c85f6e0468ceca42a20",
"sha1": "d3486ae9136e7856bc42212385ea797094475802",
"sha256": "c0535e4be2b79ffd93291305436bf889314e4a3faec05ecffcbb7df31ad9e51a"
}
}
Файл resources.json также важен: обращайте внимание на любые исполняемые ресурсы (например, с "type": "PE32 executable (GUI) Intel 80386, for MS Windows").
Некоторые скрипты в сети, как было замечено, используют new Date().getYear() вместо new Date().getFullYear(). Если образец не проявляет подозрительного поведения, обратите внимание на проверки Date.
Если вы столкнулись с файлами .JSE, скомпилируйте декодер и запустите его так:
cc decoder.c -o decoder
./decoder foo.jse bar.js
node run bar.js
Время от времени вы можете столкнуться с неподдерживаемыми компонентами. В этом случае вы можете создать issue на GitHub или эмулировать компонент самостоятельно, если знаете JavaScript.
Ошибка обычно выглядит так (номера строк могут отличаться):
1 Jan 00:00:00 - Unknown ActiveXObject WinHttp.WinHttpRequest.5.1
Trace
at kill (/home/CapacitorSet/box-js/run.js:24:10)
at Proxy.ActiveXObject (/home/CapacitorSet/box-js/run.js:75:4)
at evalmachine.<anonymous>:1:6471
at ContextifyScript.Script.runInNewContext (vm.js:18:15)
at ...
Видно, что исключение возникло в Proxy.ActiveXObject, который выглядит так:
function ActiveXObject(name) {
name = name.toLowerCase();
/* ... */
switch (name) {
case "wscript.shell":
return require("./emulator/WScriptShell");
/* ... */
default:
kill(`Unknown ActiveXObject ${name}`);
break;
}
}
Добавьте новый case "winhttp.winhttprequest.5.1" (обратите внимание на нижний регистр!) и заставьте его возвращать объект ES6 Proxy (например, ProxiedWinHttpRequest). Это используется для перехвата нереализованных функций, как только они запрашиваются вредоносным образцом:
/* emulator/WinHttpRequest.exe */
const lib = require("../lib");
module.exports = function ProxiedWinHttpRequest() {
return new Proxy(new WinHttpRequest(), {
get: function(target, name, receiver) {
switch (name) {
/* Добавьте сюда "особые" ловушки с помощью case */
default:
if (name in target) return target[name];
else lib.kill(`WinHttpRequest.${name} not implemented!`)
}
}
})
}
function WinHttpRequest() {
}
Повторите анализ: он снова завершится ошибкой, сообщив, что именно не было реализовано.
1 Jan 00:00:00 - WinHttpRequest.open not implemented!
Trace
at kill (/home/CapacitorSet/box-js/run.js:24:10)
at Object.ProxiedWinHttpRequest.Proxy.get (/home/CapacitorSet/box-js/run.js:89:7)
Эмулируйте WinHttpRequest.open по мере необходимости:
function WinHttpRequest() {
this.open = function(method, url) {
URLLogger(method, url);
this.url = url;
}
}
и повторяйте до тех пор, пока код не будет эмулироваться без ошибок.
@CapacitorSet: Оригинальный разработчик
@kirk-sayre-work: Сопровождающий
--output-directory