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

В качестве образца для анализа был выбран файл в *.doc формате. Сам файл представляет из себя эксплоит, использующий уязвимость cve-2012-0158. Разбирать будем только работу самого shellode-а, то есть только drop этап полезной нагрузки из анализируемого файла. В качестве инструментов будем использовать: Ida Pro 6.1, Python 2.7, IDE Pycharm и Far как 16-ый редактор. Также к статье будут приложены idb файл с комментариями и скрипты на python.

Разбор будет состоять из пяти этапов.

На нулевом этапе первым делом переведем shellcode из ASCII формата в бинарный, для дальнейшего его анализа в дизассемблере, длина shellcode 0xb7e. Shellcode расположен по смещению (0x388c):

1

Для перевода из одного формата в другой будем использовать скрипт написанный на python:

Теперь загрузим полученный бинарный файл в Ida Pro и по смещению 0x98 расположен код, выполняющий восстановление дельта смещение shellcode. Сам алгоритм работает следующим образом, в начале в регистр ebx помещаем последовательность байт 0xe3ff5b90, что представляет из себя набор опкодов команд: nop; pop ebx; jmp ebx. Затем регистр ebx помещается на вершину стека и адрес вершины помещается в регистр ebx и уже данный адрес вызывается командой call.

2

Данный способ помогает сбить сигнатурный детект ПО, применяемого для поиска shellcode в офисных документов, такого как officemalscanner.

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

Перейдем к первому этапу. Данный этап выполняет расшифровку очередного участка кода

3:

Алгоритм работает следующим образом, в начале восстанавливаем дельта смещение,
call $+5; pop edi, получая его, определяем начало блока, который необходимо расшифровать, затем выполняем набор из 3 инструкций (add, xor, sub) над каждым байтом расшифровываемого блока 0x200 раз (mov ecx, 200h; dec ecx;) и переходим на следующий этап.

Данный алгоритм на python:

На втором этапе восстановим таблицу импорта, в начале получим ImageBase kernel32.dll через Process Enviroment Block :4

Затем вызываем функцию, переименованную в процессе анализа в RestoreMainCode, в качестве аргумента передадим указатель на массив с хэшами имен функции, которые будет импортировать shellcode.

5

Затем вызывается функция RestoreImport 14 раз (push 14, pop ecx):

6

которая проходит по всей таблицы экспорта kernel32, и над каждым экспортируемым именем функции применяем хэширование и сравниваем, полученный хэш с элементом из массива, преданным в качестве аргумента в функцию RestoreMainCode, в случае совпадения получаем имя импортируемой функции. Хэш получаем путем сдвига на 7 бит имени функции.

Все это продублировано в скриптах:

1) GetExportDll.py — пройдем по экспорту kernel32.dll и получим имена всех функций;

2) Затем над этими именами проведем процедуру хэширования и сравним полученные хеши с теми, которые были в самом shellcode:

3) ApiHashName.py — библиотека из которой вызываем функцию хэширования:

Затем ищем среди открытых файлов  файл с shellcode-ом, перебирая все handle и проверяя, что длина файла позволяет установить указатель на длину 0x4e28 (SetFilePointer), дальше считаем четыре байта по этому смещению и сравниваем их с 0x41424344, в случае если все эти проверки прошли считаем оставшийся файл в область выделенную через VirtualAlloc, расшифруем это область методом гаммирования с ключом 0xe3 и продолжим выполнение.7

На третьем этапе выполняется drop этап основного payload на зараженный компьютер:

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

При вызове каждой функции в начале выполняем ее пролог затем записываем на стек адрес возврата и переходим к выполнению самой функции, перепрыгивая через 5 байт (размер пролога).

8Последовательность вызова этих функций, считывает из основного *.doc файла еще три файла и записывает их на диск.

Алгоритм на python:

На четвертом этапе расшифровываем очередной участок кода, реализуем данный алгоритм на python:

На пятом этапе также произведем восстановление очередного куска таблицы импорта, таким же способом как и на втором этапе, затем переместим файл T в i.dll (MoveFileA) во временную папку, запишем ее в автозагрузку, и запустим эту библиотеку через LoadLibrary.

9

И так подводя итог всего вышенаписанного, нужно обязательно подчеркнуть, что все рассмотренные этапы работы shellcode направлены на обход антивирусных средств и внося изменения в такие параметры, например как ключ шифрования можно генерировать такие shellcode не прикладывая больших усилий, но используя при этом различную полезную нагрузку. Также многие из применяемых здесь технологий возможно помогут обойти  методы статического анализа, основанные на применении какого-либо ПО направленного на поиск shellcode.

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