Мы в JSOC CERT ежедневно сталкиваемся с событиями из разных песочниц, которые функционируют в составе AntiAPT-решений наших заказчиков и пропускают через себя тысячи файлов из web- и почтового трафика. Стоит отметить, что современные Sandbox-системы в своем развитии ушли намного дальше, чем простой перехват системных вызовов в Kernel Mode и API-функций в User Mode. Все чаще в них используются собственный гипервизор, система эмуляции пользовательской активности, динамическая инструментация, хэширование и кластеризация по участкам кода, анализ покрытия кода и т.д. Такое разнообразие технологий создает иллюзию, что если какой-то файл не отработал в песочнице и не показал свое «истинное лицо», то это наверняка APT или инновационная технология обнаружения виртуального окружения, о котором ИБ-сообществу еще не известно. Но…
Так как мы не знаем внутренних особенностей работы коммерческих песочниц, в некоторых случаях мы делаем double-check – вручную анализируем сэмплы, прошедшие проверку. За последнее время мы несколько раз столкнулись с тем, что некоторые коммерческие песочницы (по объективным причинам мы не можем сказать, какие) при динамическом анализе не детектировали определённые вредоносные файлы и, если статический анализатор тоже молчал, файл и вовсе пропускался.
Проверку в песочнице удалось обойти таким известным семействам вредоносного ПО, как Pony, Loki и Hawkeye. Объединяло их лишь одно — они были накрыты упаковщиком, написанным на Visual Basic.
Учитывая, что эти семейства ВПО уже давно не являются чем-то новым, «положительный» вердикт песочниц весьма удручает. Поэтому мы решили описать общий принцип работы этого упаковщика и наблюдения, сделанные нами на протяжении некоторого времени.
Общая схема работы упаковщика условно разделена на 4 стадии и изображена на схеме ниже.
Точка входа вредоносного файла выглядит типично для приложений на Visual Basic:
Мы встречали различные варианты данного упаковщика, и код VB Wrapper часто менялся, но выполняемая задача оставалась той же: передать управление коду Stage 1. В более ранних образцах передача управления производилась посредством API-функций класса Enum* (например, EnumWindows, EnumCalendarInfo и т.д), у которых в качестве параметра указывался адрес Stage 1 кода. В последнее время наблюдаем, что управление передается напрямую.
1 этап
Управление получает код Stage 1. Данный код не зашифрован, но обфусцирован. Методы обфускации варьируются от сэмпла к сэмплу, но общий алгоритм работы не меняется:
- Цикл с множеством (в том числе и мусорных) инструкций, который вырабатывает необходимый для расшифровки кода Stage 2 ключ. Особенность этого фрагмента кода заключается в том, что там отсутствуют Sleep-функции, но за счет большого количества итераций его выполнение занимает в среднем 1-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 происходит проверка командной строки на соответствие специальному формату. Если проверка не проходит, то выполняются следующие действия:
1) Вызывается функция CreateProcess с флагом CREATE_SUSPENDED для перезапуска текущего процесса. При этом командная строка имеет необходимый формат.
2) С помощью функций GetContextThread и SetContextThread точка входа изменяется на новую, которая находится в коде Stage 1.
3) Повторяются этапы 1 и 2 (включая длительный цикл и все проверки). В этот раз проверка командной строки проходит успешно и процесс переходит к следующему этапу.
3 этап
На этом этапе расшифровывается тело основного вируса и выполняется техника Process Hollowing на текущий процесс, после чего управление передается на точку входа основного вируса.
Lesson Learned
Точно сказать, что в данном случае вызывает проблемы у той или иной песочницы мы не можем, но хочется верить, что возможность использования вредоносным ПО техник, описанных в статье, давно предусмотрена вендорами, и проблема кроется лишь в длительной временной задержке на первом этапе работы упаковщика.
Несмотря на то, что современные песочницы в большинстве своем позиционируются как часть систем защиты от APT-атак, наши наблюдения говорят о том, что даже широко известные сообществу вредоносные семейства проникают внутрь инфраструктуры с завидным постоянством. Так как нет гарантий, что сэмпл, который обошел песочницу, не будет иметь в арсенале пару техник по обходу антивируса, полагаться только на эту связку защитных решений нельзя. В таких случаях обеспечить своевременное реагирование и минимизацию потенциального ущерба может правильно выстроенный процесс мониторинга, включающий в себя события информационной безопасности с конечных хостов.
Автор: JSOC_CERT