Хабрахабр

Как вредоносы обходят песочницы с помощью Visual Basic

Мы в JSOC CERT ежедневно сталкиваемся с событиями из разных песочниц, которые функционируют в составе AntiAPT-решений наших заказчиков и пропускают через себя тысячи файлов из web- и почтового трафика. Стоит отметить, что современные Sandbox-системы в своем развитии ушли намного дальше, чем простой перехват системных вызовов в Kernel Mode и API-функций в User Mode. Все чаще в них используются собственный гипервизор, система эмуляции пользовательской активности, динамическая инструментация, хэширование и кластеризация по участкам кода, анализ покрытия кода и т.д. Такое разнообразие технологий создает иллюзию, что если какой-то файл не отработал в песочнице и не показал свое «истинное лицо», то это наверняка APT или инновационная технология обнаружения виртуального окружения, о котором ИБ-сообществу еще не известно. Но…

Так как мы не знаем внутренних особенностей работы коммерческих песочниц, в некоторых случаях мы делаем double-check – вручную анализируем сэмплы, прошедшие проверку. За последнее время мы несколько раз столкнулись с тем, что некоторые коммерческие песочницы (по объективным причинам мы не можем сказать, какие) при динамическом анализе не детектировали определённые вредоносные файлы и, если статический анализатор тоже молчал, файл и вовсе пропускался.

Объединяло их лишь одно — они были накрыты упаковщиком, написанным на Visual Basic. Проверку в песочнице удалось обойти таким известным семействам вредоносного ПО, как Pony, Loki и Hawkeye.

Поэтому мы решили описать общий принцип работы этого упаковщика и наблюдения, сделанные нами на протяжении некоторого времени.
Общая схема работы упаковщика условно разделена на 4 стадии и изображена на схеме ниже. Учитывая, что эти семейства ВПО уже давно не являются чем-то новым, «положительный» вердикт песочниц весьма удручает.

Точка входа вредоносного файла выглядит типично для приложений на Visual Basic:

В более ранних образцах передача управления производилась посредством API-функций класса Enum* (например, EnumWindows, EnumCalendarInfo и т.д), у которых в качестве параметра указывался адрес Stage 1 кода. Мы встречали различные варианты данного упаковщика, и код VB Wrapper часто менялся, но выполняемая задача оставалась той же: передать управление коду Stage 1. В последнее время наблюдаем, что управление передается напрямую.

1 этап

Управление получает код Stage 1. Данный код не зашифрован, но обфусцирован. Методы обфускации варьируются от сэмпла к сэмплу, но общий алгоритм работы не меняется:

  1. Цикл с множеством (в том числе и мусорных) инструкций, который вырабатывает необходимый для расшифровки кода Stage 2 ключ. Особенность этого фрагмента кода заключается в том, что там отсутствуют Sleep-функции, но за счет большого количества итераций его выполнение занимает в среднем 1-2 минуты.
  2. Расшифровка (обычный XOR) и передача управления коду Stage 2.

На скриншоте ниже приведены примеры используемых методов обфускации:

2 этап

Основной задачей кода в Stage 2 является проверка окружения и реализация методов антиотладки. Некоторые участки кода зашифрованы (расшифровываются перед выполнением, а после – зашифровываются обратно все тем же алгоритмом XOR) для затруднения детектирования по сигнатурам. После расшифровки видны характерные признаки, по которым код Stage 2 можно узнать при ручном анализе.

Список проверок довольно большой и отличается в разных версиях упаковщика, поэтому мы приведем несколько методов, которые встречались во всех версиях, со скриншотами, а в конце перечислим весь список в таблице.

1) GetTickCount + Sleep

Берется текущая метка времени, вызывается Sleep на 2 секунды, после чего сразу же берется еще одна метка времени.

После этого проверяется разница между метками (на самом ли деле прошло 2 секунды).

2) SetErrorMode

Проверяется правильность работы API-вызова SetErrorMode. Функция вызывается два раза подряд с параметрами 0x800 и 0x0, после чего результат второго вызова проверяется: он должен быть равен 0x800.

3) SetLastError

Сначала вызывается SetLastError с параметром 0x5, после чего проверяется, что значение Last error code в TEB правильно установилось (то есть, равно 0x5).

4) Проверка движения курсора

Код входит в бесконечный цикл, ожидающий передвижения указателя мыши.

5) DbgBreakPoint и DbgUiRemoteBreakin

Данные функции модифицируются, чтобы помешать отладчику подсоединиться к процессу.

Техника

Комментарий

GetTickCount + Sleep

Проверка временных меток

SetErrorMode

Проверка правильной работы функции

SetLastError

Проверка правильной работы функции

GetCursorPos

Проверка движения курсора

DbgBreakPoint

Модификация функции для запрета присоединения отладчика

DbgUiRemoteBreakin

Модификация функции для запрета присоединения отладчика

Hook Deletion

Восстанавливаются первые 5 байт функций в ntdll.dll на случай, если там стоят хуки

NtSetInformationThread

Параметр 0x11 (ThreadHideFromDebugger)

GetThreadContext + check DR

Проверяются отладочные регистры DR0-DR3, DR6, DR7

Check breakpoints

Проверяются инструкции INT3 (0xCC), int 3 (0xCD 0x03) и ud2 (0x0F 0x0B) в начале некоторых функций

cpuid (EAX=0x0)

Проверяются регистры EAX, ECX, EDX

cpuid (EAX=0x40000000)

Проверяются регистры EAX, ECX, EDX

cpuid (EAX=0x1)

Проверяется 31-й бит ECX

PEB (BeingDebugged)

Проверяется значение 0x1

PEB (NtGlobalFlag)

Проверяется значение 0x70

NtQueryInformationProcess

Вызывается с флагами ProcessDebugPort (0x7), ProcessDebugFlags (0x1F), ProcessDebugObjectHandle (0x1E)

Process Name Check

Проверяются строки «sample», «sandbox», «virus», «malware», «self.»

В случае выполнения всех техник этапа 2 происходит проверка командной строки на соответствие специальному формату. Если проверка не проходит, то выполняются следующие действия:

При этом командная строка имеет необходимый формат.
2) С помощью функций GetContextThread и SetContextThread точка входа изменяется на новую, которая находится в коде Stage 1.
3) Повторяются этапы 1 и 2 (включая длительный цикл и все проверки). 1) Вызывается функция CreateProcess с флагом CREATE_SUSPENDED для перезапуска текущего процесса. В этот раз проверка командной строки проходит успешно и процесс переходит к следующему этапу.

3 этап

На этом этапе расшифровывается тело основного вируса и выполняется техника Process Hollowing на текущий процесс, после чего управление передается на точку входа основного вируса.

Lesson Learned

Точно сказать, что в данном случае вызывает проблемы у той или иной песочницы мы не можем, но хочется верить, что возможность использования вредоносным ПО техник, описанных в статье, давно предусмотрена вендорами, и проблема кроется лишь в длительной временной задержке на первом этапе работы упаковщика.

Так как нет гарантий, что сэмпл, который обошел песочницу, не будет иметь в арсенале пару техник по обходу антивируса, полагаться только на эту связку защитных решений нельзя. Несмотря на то, что современные песочницы в большинстве своем позиционируются как часть систем защиты от APT-атак, наши наблюдения говорят о том, что даже широко известные сообществу вредоносные семейства проникают внутрь инфраструктуры с завидным постоянством. В таких случаях обеспечить своевременное реагирование и минимизацию потенциального ущерба может правильно выстроенный процесс мониторинга, включающий в себя события информационной безопасности с конечных хостов.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»