Данной записью я продолжаю
начатый ранее экскурс в legacy-мусор графической подсистемы Windows и уязвимости нулевого дня в ней. На этот раз речь пойдёт об уязвимостях, связанных с обработкой шрифтов. Вообще данный вектор сложно назвать новым, в ядре Windows уже неоднократно находили подобные уязвимости, среди них наиболее известными являются
MS11-077 и
MS11-087, подробный анализ которых можно найти в документе «
GDI Font Fuzzing in Windows Kernel for Fun».
Операционная система Windows поддерживает как растровые, так и векторные шрифты. Растровые шрифты представляют собой файлы формата Microsoft Windows Bitmapped Font с расширением .FON, в качестве контейнера для хранения данных шрифта используется формат Portable Executable (обычные PE-файлы, так же как и в случае с клавиатурными раскладками). В неправильной обработке шрифтов такого формата, которая приводит к переполнению пула в ядре, и заключается уязвимость MS11-077.
Векторные шрифты Windows в качестве контейнера используют формат
OpenType, а относительно формата хранимых в контейнере данных такие шрифты делятся на два класса:
TrueType-based (файлы с расширением .TTF) и
PostScript-based (файлы с расширением .OTF). Спецификация на OpenType и TrueType форматы
доступна на сайте Microsoft-а. Эксплойт для уязвимости MS11-087, при обработке TrueType-based шрифтов, использовался в черве
Duqu.
Вообще, на поиск других уязвимостей при обработке шрифтов меня (да и, наверняка, многих других исследователей) подвигли именно MS11-077 и MS11-087. Из-за простоты проработки данного вектора (которая диктуется относительно несложными форматами) я не рассчитывал на существенный успех, и сосредоточился, главным образом, на PostScript-based шрифтах, в коде обработки которых мне и удалось найти неизвестную ранее remote DoS уязвимость.
OpenType контейнер и обработка шрифтов в Windows
Данный формат описан в главе «TrueType Font File» документа «TrueType Specification». Его структура включает в себя последовательно идущие друг за другом заголовок, таблицу директорий и, собственно, сами директории:
Заголовок имеет следующий вид:
typedef struct _OTF_FILE_HEADER
{
ULONG sfntVersion; // 0x00010000 for version 1.0.
USHORT numTables; // Number of tables.
USHORT searchRange; // (Maximum power of 2 <= numTables) x 16.
USHORT entrySelector; // Log2(maximum power of 2 <= numTables).
USHORT rangeShift; // NumTables x 16-searchRange.
} OTF_FILE_HEADER,
*POTF_FILE_HEADER;
Наиболее важным для реализации фаззера полем является numTables, которое содержит количество записей в таблице директорий. Каждая такая запись имеет следующую структуру:
typedef struct _OTF_TABLE_HEADER
{
ULONG tag; // 4-byte identifier.
ULONG checkSum; // CheckSum for this table.
ULONG offset; // Offset from beginning of TrueType font file.
ULONG length; // Length of this table.
} OTF_TABLE_HEADER,
*POTF_TABLE_HEADER;
Идентификатор tag представляет собой 4 ASCII символа, которые являются именем таблицы (например: head, hhea, maxp, OS/2, name, cmap, post, CFF, hmtx). Именно по этому имени код обрабатывающий файл шрифта определяет, какие данные находятся в данной таблице (описания глифов, метаинформация, цифровая подпись и многое другое). Всего типов таблиц существует около двух десятков. Загрузчик шрифтов проверяет контрольные суммы таблиц, которые хранятся в поле checkSum, если контрольная сумма не совпадает – то такой файл шрифта обработан не будет.
Код подсчёта контрольной суммы для данных, хранящихся в таблице:
ULONG OTF_CalcTableChecksum(ULONG *Table, ULONG Length)
{
ULONG Sum = 0;
ULONG nLongs = (ALIGN_UP(Length, sizeof(ULONG))) / sizeof(ULONG);
for (ULONG i = 0; i < nLongs; i++, Table++)
{
Sum += htonl(*Table);
}
return Sum;
}
Для загрузки произвольного шрифта в Windows используются API функции
AddFontResource() и
AddFontresourceEx(), которые в качестве параметра принимают путь к файлу шрифта. На низком уровне этим функциям соответствуют системные вызовы графической подсистемы win32k!NtGdiAddFontResourceW() и win32k!NtGdiAddFontMemResourceEx(). Последний позволяет загрузить шрифт не только из файла на диске, но так же из буфера в памяти.
За обработку TrueType-based шрифтов отвечает код непосредственно графической подсистемы, находящийся в исполняемом модуле win32k.sys, но обработка PostScript-based шрифтов вынесена в динамическую библиотеку %SystemRoot%\system32\atmfd.dll, разработчиком которой, согласно информации о версии, является компания Adobe:
Эта библиотека имеет один и тот же номер версии на всех актуальных версиях Windows, начиная с XP. Загрузка atmfd.dll осуществляется на этапе инициализации графической подсистемы в коде win32k!InitializeGreCSRSS() c помощью функции win32k!bEnableFontDriver():
loc_BF88BF89: ; CODE XREF: InitializeGreCSRSS()+B92
push 4
push offset _atmfdEnableDriver@12 ; __int32 (__stdcall *)()
call ?bEnableFontDriver@@YGHP6GJXZK@Z ; bEnableFontDriver(long (*)(void),ulong)
test eax, eax
jz short loc_BF88BFF8
Для вызова того или иного кода из atmfd.dll графическая подсистема использует функции-переходники, адреса которых хранятся в глобальном массиве win32k!atmfdCallBlock():
_atmfdCallBlock ; DATA XREF: atmfdEnableDriver(x,x,x)+16o
dd 0
dd offset _atmfdEnablePDEV@44 ; atmfdEnablePDEV(x,x,x,x,x,x,x,x,x,x,x)
dd 2
dd offset _atmfdDisablePDEV@4 ; atmfdDisablePDEV(x)
dd 1
dd offset __SetDbgTag@8 ; _SetDbgTag(x,x)
dd 2Dh
dd offset _atmfdLoadFontFile@28 ; atmfdLoadFontFile(x,x,x,x,x,x,x)
dd 2Ch
dd offset _atmfdQueryFontCaps@8 ; atmfdQueryFontCaps(x,x)
dd 2Eh
dd offset _atmfdUnloadFontFile@4 ; atmfdUnloadFontFile(x)
dd 33h
dd offset _atmfdQueryFontFile@16 ; atmfdQueryFontFile(x,x,x,x)
dd 1Ah
dd offset _atmfdQueryFont@16 ; atmfdQueryFont(x,x,x,x)
dd 2Ah
dd offset _atmfdFree@8 ; atmfdFree(x,x)
dd 1Bh
dd offset _atmfdQueryFontTree@20 ; atmfdQueryFontTree(x,x,x,x,x)
dd 1Ch
dd offset _atmfdQueryFontData@28 ; atmfdQueryFontData(x,x,x,x,x,x,x)
dd 2Bh
dd offset _atmfdDestroyFont@4 ; atmfdDestroyFont(x)
dd 35h
dd offset _atmfdQueryAdvanceWidths@24 ; atmfdQueryAdvanceWidths(x,x,x,x,x,x)
dd 31h
dd offset _atmfdQueryTrueTypeOutline@28 ; atmfdQueryTrueTypeOutline(x,x,x,x,x,x,x)
dd 30h
dd offset _atmfdQueryTrueTypeTable@32 ; atmfdQueryTrueTypeTable(x,x,x,x,x,x,x,x)
dd 18h
dd offset _atmfdEscape@24 ; atmfdEscape(x,x,x,x,x,x)
dd 2Fh
dd offset _atmfdFontManagement@28 ; atmfdFontManagement(x,x,x,x,x,x,x)
dd 32h
dd offset _atmfdGetTrueTypeFile@8 ; atmfdGetTrueTypeFile(x,x)
dd 56h
dd offset _atmfdQueryGlyphAttrs@8 ; atmfdQueryGlyphAttrs(x,x)
Отладочные символы к библиотеке atmfd.dll отсутствуют, она имеет размер около 300Кб и содержит в себе 837 функций. В коде atmfd.dll обильно встречается вывод различных диагностических сообщений об ошибках следующего вида:
push offset aOp_spOp_stk ; "op_sp >= op_stk"
push offset aUnderflowOfTyp ; "underflow of Type 1 operand stack"
push 117Bh
push offset aDNtWindowsCo_6 ; "d:\\nt\\windows\\core\\ntgdi\\fondrv\\otfd\\bc"...
push offset aSDSS ; "%s:%d: %s (%s)\n"
push offset word_427FC
call nullsub_52
Однако функция, осуществляющая вывод этих сообщений, в связи с особенностью Release-сборки представляет собой ничего не делающую пустышку. Перенаправить вывод этих сообщений в удалённый отладчик ядра можно путём установки следующей точки останова:
kd> ba e1 atmfd+15384 "kb L1;da poi(esp+c);da poi(esp+14);g"
Диагностические сообщения могут быть полезными при фаззинге и анализе его результатов:
Фаззинг
Так как тратить много времени на несколько заезженный вектор было неразумно – искать уязвимости при обработке PostScript-based шрифтов я решил методом примитивного мутационного фаззинга. Разработанный мной фаззер, разумеется, осуществлял корректный пересчёт контрольных сумм для содержимого таблиц OpenType контейнера, а во всём остальном – был основан на базе инструмента MutateGen,
о котором я когда-то писал в контексте фаззинга формата архивов. Итератор (код, который осуществляет «запуск» сгенерированного набора тестовых данных) был встроен в сам фаззер, и представлял собой вариацию на тему API функций AddFontResource() и DrawText().
Касательно реализации итератора у меня есть некоторые общие замечания. В книге «
iOS Hacker’s Handbook», которую я сейчас читаю (а так же во многих других подобной тематики), содержатся рекомендации по реализации итератора вида «передайте сгенерированную фаззером единицу данных тестируемому приложению, подождите N секунд, после чего насильно завершите его процесс». На мой взгляд, подобный подход – несколько бестолковый. Так как количество итераций, которые ваш сетап для фаззинга может производить в течении некоторого интервала времени, самым непосредственным образом влияют на эффективность фаззинга – разумно минимизировать время проведения одной итерации всеми возможными средствами, а именно – завершать работу тестируемого приложения не по истечению фиксированного количества времени, а ровно в тот момент, когда оно закончило загрузку и обработку тестовых данных. Для отслеживания этого момента можно использовать как легитимные средства (например, различные API и плагины) так и хаки, вроде внесения собственных модификаций в исходный код или исполняемый файл тестируемого приложения.
В итераторе своего фаззера шрифтов, для отслеживания момента окончания загрузки шрифта, я использовал особенности естественного поведения очереди оконных сообщений в Windows:
- При создании окна с помощью API функции CreateWindowEx() система посылает в его оконную процедуру сообщения типа WM_PAINT.
- Сразу после создания окна код фаззера отправляет ему сообщение типа WM_COMMAND.
- При получении сообщения WM_PAINT оконная процедура инициирует вывод текста с использованием модифицированного фаззером шрифта. Для этого вызываются API функции CreateFontIndirect() и DrawText().
- Так как синхронные оконные сообщения доставляются оконной процедуре в порядке добавления их в очередь – после WM_PAINT оконная процедура получает сообщение WM_COMMAND, обработка которого заключается в закрытии окна и завершении тестовой итерации. Загрузка шрифта и вывод текста в этот момент уже завершились.
Фаззер представляет собой приложение, запускаемое из командной строки:
> MsFontsFuzz.exe <font_name> <font_file_path> [options]
... где <font_name> и <font_file_path> – имя шрифта и путь к его файлу. В качестве опций можно указывать следующие опциональные ключи:
--test – вывод символов указанного шрифта без фаззинга.
--text – строка, которая будет выведена с использованием указанного шрифта, по умолчанию используется строка ASCII символов в диапазоне 20h – 7Fh.
--noisy – выводить в консоль информацию о каждой итерации.
--fix_crcs – исправление неправильных контрольных сумм в указанном файле шрифта.
Так же поддерживаются ключи управления режимом генерации некорректных данных (
-FILE_RANGE_START,
-FILE_RAGE_END,
-BLOCK_SIZE,
-BLOCK_RANGE_START,
-BLOCK_RANGE_END и
-BLOCK_RANGE_N) которые соответствуют таковым у упоминавшегося выше инструмента MutateGen.
В качестве исходных данных для мутационного генератора я выбрал шрифты
Brush Script Std Regular,
Hobo Std Medium и несколько других. Так как публичных инструментов для анализа покрытия кода в режиме ядра не существует – этот выбор был интуитивным, исходя из критериев наименьшего размера файла шрифта при наибольшем количестве директорий разных типов в нём.
Уязвимость
В процессе фаззинга c использованием шрифтов Brush Script Std Regular и Hobo Std Medium несколько раз обнаруживалось полное «зависание» тестовой виртуальной машины с последующим вылетом в удалённый отладчик режима ядра по срабатыванию watchdog-а:
*******************************************************************************
* *
* The watchdog detected a timeout condition. We broke into the debugger to *
* allow a chance for debugging this failure. *
* *
* Normally the system will try to recover from this failure and return to a *
* VGA graphics mode. To disable the recovery feature edit the watchdog *
* variable WdDisableRecovery. This will allow you to debug your driver. *
* i.e. execute ed watchdog!WdDisableRecovery 1. *
* *
* Intercepted bugcheck code and arguments are listed below this message. *
* You can use them the same way as you would in case of the actual break, *
* i.e. execute .thread Arg1 then kv to identify an offending thread. *
* *
*******************************************************************************
*** Intercepted Fatal System Error: 0x000000EA
(0x823D8920,0x82809008,0x82954E78,0x00000001)
Driver at fault: vmx_fb
Break instruction exception - code 80000003 (first chance)
nt!DbgBreakPoint:
80527c00 cc int 3
kd> .thread 0x823D8920
Implicit thread is now 823d8920
kd> kb
ChildEBP RetAddr Args to Child
b194f694 806d3ca4 00000000 b194fdf0 8054160d nt!KiDispatchInterrupt+0x7f
b194f6a0 8054160d 00c60b00 00000162 b194fdf0 hal!HalEndSystemInterrupt+0x54
b194f6a0 bf1b4dbc 00c60b00 00000162 b194fdf0 nt!KiInterruptDispatch+0x4d
*** ERROR: Module load completed but symbols could not be loaded for ATMFD.DLL
WARNING: Stack unwind information not available. Following frames may be wrong.
b194fdf0 bf1b6f4a e1326868 bf1c4828 b1950028 ATMFD+0x2adbc
b194fea8 bf1aaf74 e1326868 bf1c4828 b1950028 ATMFD+0x2cf4a
b194ff88 bf1ab013 e1326868 b1950028 b19500ac ATMFD+0x20f74
b194ffb4 bf19c38f e1326868 bf1c4828 b1950028 ATMFD+0x21013
b195011c bf19c77a ffffffff b1950220 e12acb58 ATMFD+0x1238f
b1950168 bf18d386 ffffffff b1950220 00000000 ATMFD+0x1277a
b19501c0 bf83a9db e1a91010 e12abd08 00000001 ATMFD+0x3386
b19501f0 bf83ac37 e1a91010 e12abd08 00000001 win32k!PDEVOBJ::QueryFontData+0x3c
b1950268 bf807b15 b19505d0 e13df344 00000063 win32k!xInsertMetricsPlusRFONTOBJ+0xc4
b195029c bf812b58 00000001 b1950644 7ffde22c win32k!RFONTOBJ::bGetGlyphMetricsPlus+0x180
b19502d0 bf812624 b1950858 b19505d0 00002128 win32k!ESTROBJ::vCharPos_H3+0xee
b1950314 bf8118da 7ffde22c 00000001 b1950858 win32k!ESTROBJ::vInit+0x257
b19505b8 bf813031 b1950858 000000ed 00000000 win32k!GreExtTextOutWLocked+0x666
b1950720 bf80c6c7 b1950858 7ffde1dc 00000058 win32k!GreBatchTextOut+0x344
b1950874 8053d6aa 00000091 00a8fabc 00a8fadc win32k!NtGdiFlushUserBatch+0x11b
b19508a4 bf80555e bf80556b 00000000 00a80000 nt!KiFastCallEntry+0xca
b19508ac 00000000 00a80000 7c900023 badb0023 win32k!HmgDecProcessHandleCount+0x2e
Уязвимость стабильно воспроизводилась в результате модификации фаззером одного из байтов в директории CFF. Всего подобных смещений, изменения байта по которым приводили к триггерингу уязвимости, обнаружилось несколько штук для каждого из шрифтов. Одно из них:
В директории CFF, согласно документации, находятся данные в формате Compact Font Format, спецификация на который
предоставляется компанией Adobe. Внутри CFF контейнера содержится векторное описание глифов для символов шрифта в формате Post Script Type 2 Character String Format, который так же описан в документе «
The Type 2 Charstring Format»:
Формат CFF организован в отдельные структуры данных, которые содержат описания поддерживаемых данным шрифтом символов, вектора для построения глифов, метаинформацию и прочее. Доступ к глифам осуществляется через таблицы кодирования, которые устанавливают соответствие между глифами и кодами символов. Эти таблицы представлены в виде 3-х параллельных массивов (код символа, имя символа, глиф) с общим индексом.
Для работы с PostScript шрифтами Adobe предоставляет пакет
Font Development Kit, в который входит ряд полезных программ, позволяющих разбирать и собирать обратно PostScript шрифты. Для локализации некорректных данных я сделал текстовые дампы содержимого для нормального и сгенерированного фаззером шрифта с помощью утилиты tx.exe, после чего сравнил их diff-ом:
> fdk-2.5\Tools\win\tx.exe -dcf BrushScriptStd.otf > BrushScriptStd.txt
> fdk-2.5\Tools\win\tx.exe -dcf BrushScriptStd_0000298f.otf > BrushScriptStd_0000298f.txt
> diff -u BrushScriptStd.txt BrushScriptStd_0000298f.txt
--- BrushScriptStd.txt Fri Jun 08 14:56:35 2012
+++ BrushScriptStd_0000298f.txt Fri Jun 08 17:06:00 2012
@@ -1249,7 +1249,8 @@
[68]={
-40 -13 88 310 -20 hstem
-3 73 14 callsubr
- 95 112 99 65 61 vhcurveto
+ 95 112 99 65 reserved13
+ vhcurveto
32 callsubr
}
Дампы доступны для загрузки по следующим ссылкам:
BrushScriptStd_0000298f.txt,
BrushScriptStd.txt
Как видно, модификация фаззером значения байта по смещению 298Fh из C8h в 0Dh привела к тому, что описание глифа #68 (в шрифте Brush Script Std ему соответствует прописная латинская литера «с») изменилось с:
[68]={
-40 -13 88 310 -20 hstem
-3 73 14 callsubr
95 112 99 65 61 vhcurveto
32 callsubr
}
… на:
[68]={
-40 -13 88 310 -20 hstem
-3 73 14 callsubr
95 112 99 65 reserved13
vhcurveto
32 callsubr
}
Что и привело к аномальному поведению atmfd.dll при обработке шрифта.
Обратимся к документации на Type 2 Charstring Format, что бы разобраться в формате глифов и выяснить причину уязвимости. Charstring-данные представляют собой массив байтов, каждый из которых может декодироваться либо как оператор (hstem, callsubr, vhcurveto и другие на листингах выше), либо как числовой аргумент (-40, -13, 88, 310, -20 и так далее) в зависимости от того, в каком диапазоне лежит значение этого байта:
Данные оригинального шрифта, имеющие HEX-представление
F7h 04h EEh CCh C8h 1Eh, декодируются в команду
|dy1 dx2 dy2 dx3 dyf vhcurveto| которая строит к текущей точке кривую Безье по двум касательным, которые указаны в качестве операндов. Операнд dyf (глубина изгиба кривой), в модифицированном фаззером шрифте имеет значение 0Dh, в результате чего atmfd.dll ошибочно декодирует этот байт в зарезервированный оператор под номером 13:
Для более удобного анализа уязвимости из сгенерированного фаззером шрифта я собрал минимальный тестовый кейс, с помощью которого можно воспроизвести найденную уязвимость. Для редактирования шрифтов была использована другая утилита из состава Font Development Kit, ttx.exe, которая позволяет преобразовать .OTF файл шрифта в XML представление, и генерировать из модифицированного XML документа новый .OTF файл.
Модификации для получения минимального тестового кейса свелись к следующему:
- Убрана вся метаинформация.
- Оставлен только один глиф.
- Оригинальные команды Type 2 Charstring Format были изменены путём свёртки вызовов процедур (оператор callsubr) и удаления тех инструкций, которые не влияют на воспроизведение уязвимости.
В результате текстовый дамп полученного файла шрифтов упростился до следующего вида:
### Header (00000700-00000703)
major =1
minor =0
hdrSize=4
offSize=4
### Name INDEX (00000704-0000071c)
--- object[index]={value}
[0]={CFF_Type-1_0x0d_expl}
### Top DICT INDEX (0000071d-0000074c)
--- object[index]={value}
[0]={
423 version
424 Notice
425 FullName
426 FamilyName
387 Weight
-14 ItalicAngle
-184 -280 1328 882 FontBBox
465 charset
28 1271 Private
472 CharStrings
}
### String INDEX (0000074d-000008cc)
--- object[index]={value}
[391]={f_i}
[392]={Omega}
[393]={pi}
[394]={Euro}
[395]={estimated}
[396]={partialdiff}
[397]={product}
[398]={summation}
[399]={uni2219}
[400]={radical}
[401]={infinity}
[402]={integral}
[403]={approxequal}
[404]={notequal}
[405]={lessequal}
[406]={greaterequal}
[407]={lozenge}
[408]={uni02C9}
[409]={uni00AD}
[410]={uni03A9}
[411]={uni00A0}
[412]={afii61289}
[413]={uni03BC}
[414]={uni2215}
[415]={f_l}
[416]={a.superior}
[417]={o.superior}
[418]={one.superior}
[419]={two.superior}
[420]={three.superior}
[421]={uni2206}
[422]={uni2010}
[423]={002.000}
[424]={}
[425]={CFF_Type-1_0x0d_expl Medium}
[426]={CFF_Type-1_0x0d_expl}
### GlobalSubrINDEX (000008cd-000008ce)
empty
### Encoding ........ (Standard)
### Charset (000008d1-000008d7)
format=1
--- Range1[index]={first,nLeft}
[0]={1,227}
[1]={391,31}
### CharStrings INDEX (000008d8-00000bf6)
--- object[index]={value}
[0]={
endchar
}
[1]={
endchar
}
# ... SKIPPED ...
[68]={
-74 37 -72 77 95 112 99 65 reserved13
vhcurveto
endchar
}
# ... SKIPPED ...
[260]={
endchar
}
### Private DICT (00000bf7-00000c12)
-20 20 683 23 -333 23 247 9 BlueValues
-265 23 OtherBlues
88 StdHW
88 StdVW
565 defaultWidthX
399 nominalWidthX
28 Subrs
### Local Subr INDEX (00000c13-00000c14)
Empty
XML представление, которое использовалось для редактирования шрифта:
CFF_Type-1_0x0d_expl.ttx
Далее была произведена трассировка кода atmfd.dll при обработке минимального тестового кейса. При загрузке atmfd.dll в дизассемблер, основная функция, обрабатывающая байты глифа, сразу бросается в глаза: она находится по адресу ATMFD+0x288ca и имеет размер машинного кода порядка 17-ти килобайт. В коде функции неоднократно встречаются константы и арифметические операции декодирования байтов, которые описаны в документации на Type 2 Charstring Format. Установим точку останова на ту инструкцию, которая читает байт из описывающего глиф массива для последующего декодирования:
kd> u ATMFD+0x28f83
ATMFD+0x28f83:
bf1b2f83 8b857cffffff mov eax,dword ptr [ebp-84h]
bf1b2f89 0fb638 movzx edi,byte ptr [eax]
bf1b2f8c ff857cffffff inc dword ptr [ebp-84h]
kd> db @eax
00c80b2b 41 b0 43 d8 ea f7 04 ee-cc 0d 1e 0e 0e 0e 0e 0e A.C.............
00c80b3b 0e 0e 0e 0e 0e 0e 0e 0e-0e 0e 0e 0e 0e 0e 0e 0e ................
00c80b4b 0e 0e 0e 0e 0e 0e 0e 0e-0e 0e 0e 0e 0e 0e 0e 0e ................
00c80b5b 0e 0e 0e 0e 0e 0e 0e 0e-0e 0e 0e 0e 0e 0e 0e 0e ................
Регистр eax указывает на область памяти, в которой находится глиф. Когда цикл получения байт из буфера доходит до кода операции 0Dh, из-за ошибки при его декодировании указатель текущей позиции буфера перемещается на несколько десятков байт выше (0x00c80b09):
ATMFD+0x28f89:
bf1b2f89 0fb638 movzx edi,byte ptr [eax]
kd> db @eax
00c80b09 0e 0e 0e 0e 0e 0e 0e 0e-0e 0e 0e 0e 0e 0e 0e 0e ................
00c80b19 0e 0e 0e 0e 0e 0e 0e 0e-0e 0e 0e 0e 0e 0e 0e 0e ................
00c80b29 0e 0e 41 b0 43 d8 ea f7-04 ee cc 0d 1e 0e 0e 0e ..A.C...........
00c80b39 0e 0e 0e 0e 0e 0e 0e 0e-0e 0e 0e 0e 0e 0e 0e 0e ................
... где находится код операнда 0Eh (endchar), после обработки которого указатель текущей позиции вновь перемещается на начало глифа (0x00c80b2b), из-за чего процедура впадает в бесконечный цикл.
Таким образом, найденную мной уязвимость можно классифицировать как Remote DoS – по итогам исследования кода atmfd.dll не было выявлено ошибок, которые могли бы привести к повреждению памяти или контролю над EIP. На компьютерах с Windows XP / Server 2003 обработка зловредного шрифта приводит к аварийному завершению работы системы:
На Windows Vista и старше результатом воспроизведения уязвимости является 100% загрузка одного из ядер процессора, опять же, без возможности каким-либо образом завершить процесс, который инициировал загрузку зловредного шрифта:
Уязвимости подвержены все актуальные версии Windows (как x32, так и x64). Уязвимость может быть воспроизведена из-под учётной записи с любым уровнем привилегий. Для удалённой атаки зловредный шрифт можно
встроить в web-страницу или документ (червь Duqu использовал документ Microsoft Word формата .DOCX для проведения схожей атаки).
Links
Размер минимизированного .OTF файла шрифта составляет 4Кб. Архив
доступен для загрузки.
Исходные тексты и исполняемые файлы фаззера доступны
в репозитории на GitHub.