Статья Удалённый 0day в ядре Windows: вы ещё не забыли уязвимости при обработке шрифтов?

weaver

31 c0 bb ea 1b e6 77 66 b8 88 13 50 ff d3
Модератор
Регистрация
19.12.2018
Сообщения
447
Реакции
419
Баллы
64
Данной записью я продолжаю начатый ранее экскурс в 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». Его структура включает в себя последовательно идущие друг за другом заголовок, таблицу директорий и, собственно, сами директории:

FontsVuln_OpenType.gif

Заголовок имеет следующий вид:
Код:
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:

FontsVuln_atmfd.gif

Эта библиотека имеет один и тот же номер версии на всех актуальных версиях 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"
Диагностические сообщения могут быть полезными при фаззинге и анализе его результатов:

FontsVuln_atmfd-messages.gif

Фаззинг

Так как тратить много времени на несколько заезженный вектор было неразумно – искать уязвимости при обработке PostScript-based шрифтов я решил методом примитивного мутационного фаззинга. Разработанный мной фаззер, разумеется, осуществлял корректный пересчёт контрольных сумм для содержимого таблиц OpenType контейнера, а во всём остальном – был основан на базе инструмента MutateGen, о котором я когда-то писал в контексте фаззинга формата архивов. Итератор (код, который осуществляет «запуск» сгенерированного набора тестовых данных) был встроен в сам фаззер, и представлял собой вариацию на тему API функций AddFontResource() и DrawText().

Касательно реализации итератора у меня есть некоторые общие замечания. В книге «iOS Hacker’s Handbook», которую я сейчас читаю (а так же во многих других подобной тематики), содержатся рекомендации по реализации итератора вида «передайте сгенерированную фаззером единицу данных тестируемому приложению, подождите N секунд, после чего насильно завершите его процесс». На мой взгляд, подобный подход – несколько бестолковый. Так как количество итераций, которые ваш сетап для фаззинга может производить в течении некоторого интервала времени, самым непосредственным образом влияют на эффективность фаззинга – разумно минимизировать время проведения одной итерации всеми возможными средствами, а именно – завершать работу тестируемого приложения не по истечению фиксированного количества времени, а ровно в тот момент, когда оно закончило загрузку и обработку тестовых данных. Для отслеживания этого момента можно использовать как легитимные средства (например, различные API и плагины) так и хаки, вроде внесения собственных модификаций в исходный код или исполняемый файл тестируемого приложения.

В итераторе своего фаззера шрифтов, для отслеживания момента окончания загрузки шрифта, я использовал особенности естественного поведения очереди оконных сообщений в Windows:
  1. При создании окна с помощью API функции CreateWindowEx() система посылает в его оконную процедуру сообщения типа WM_PAINT.
  2. Сразу после создания окна код фаззера отправляет ему сообщение типа WM_COMMAND.
  3. При получении сообщения WM_PAINT оконная процедура инициирует вывод текста с использованием модифицированного фаззером шрифта. Для этого вызываются API функции CreateFontIndirect() и DrawText().
  4. Так как синхронные оконные сообщения доставляются оконной процедуре в порядке добавления их в очередь – после 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.

FontsVuln_Fuzzer.gif

В качестве исходных данных для мутационного генератора я выбрал шрифты 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. Всего подобных смещений, изменения байта по которым приводили к триггерингу уязвимости, обнаружилось несколько штук для каждого из шрифтов. Одно из них:

FontsVuln_0x0d-Byte.gif

В директории CFF, согласно документации, находятся данные в формате Compact Font Format, спецификация на который предоставляется компанией Adobe. Внутри CFF контейнера содержится векторное описание глифов для символов шрифта в формате Post Script Type 2 Character String Format, который так же описан в документе «The Type 2 Charstring Format»:

FontsVuln_CFF.gif

Формат 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 и так далее) в зависимости от того, в каком диапазоне лежит значение этого байта:

FontsVuln_Type2-bytes.gif

Данные оригинального шрифта, имеющие HEX-представление F7h 04h EEh CCh C8h 1Eh, декодируются в команду |dy1 dx2 dy2 dx3 dyf vhcurveto| которая строит к текущей точке кривую Безье по двум касательным, которые указаны в качестве операндов. Операнд dyf (глубина изгиба кривой), в модифицированном фаззером шрифте имеет значение 0Dh, в результате чего atmfd.dll ошибочно декодирует этот байт в зарезервированный оператор под номером 13:

FontsVuln_Type2-ops.gif

Для более удобного анализа уязвимости из сгенерированного фаззером шрифта я собрал минимальный тестовый кейс, с помощью которого можно воспроизвести найденную уязвимость. Для редактирования шрифтов была использована другая утилита из состава Font Development Kit, ttx.exe, которая позволяет преобразовать .OTF файл шрифта в XML представление, и генерировать из модифицированного XML документа новый .OTF файл.

Модификации для получения минимального тестового кейса свелись к следующему:
  1. Убрана вся метаинформация.
  2. Оставлен только один глиф.
  3. Оригинальные команды 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 обработка зловредного шрифта приводит к аварийному завершению работы системы:

FontsVuln_BSoD.gif

На Windows Vista и старше результатом воспроизведения уязвимости является 100% загрузка одного из ядер процессора, опять же, без возможности каким-либо образом завершить процесс, который инициировал загрузку зловредного шрифта:

FontsVuln_CPU.gif

Уязвимости подвержены все актуальные версии Windows (как x32, так и x64). Уязвимость может быть воспроизведена из-под учётной записи с любым уровнем привилегий. Для удалённой атаки зловредный шрифт можно встроить в web-страницу или документ (червь Duqu использовал документ Microsoft Word формата .DOCX для проведения схожей атаки).

Links

Размер минимизированного .OTF файла шрифта составляет 4Кб. Архив доступен для загрузки.

Исходные тексты и исполняемые файлы фаззера доступны в репозитории на GitHub.

Автор Сr4sh (с)
Источник
 

3r05

floppy-диск
Пользователь
Регистрация
20.11.2019
Сообщения
5
Реакции
1
Баллы
3
Nice Work Mate...!!! Good Share
 

weaver

31 c0 bb ea 1b e6 77 66 b8 88 13 50 ff d3
Модератор
Регистрация
19.12.2018
Сообщения
447
Реакции
419
Баллы
64
А проблема в том, что большинство народа не понимает что здесь написано :)
Уже работаю над этим. Есть задача наполнить контентом раздел. Привлечь народ. А так же начать разбор и обсуждение бинарных уязвимостей. Плавное вхождение для тех кому это не понятно всё, но интересно.
 

BadMonkey

floppy-диск
Пользователь
Регистрация
23.12.2019
Сообщения
3
Реакции
0
Баллы
2
Very good research. A bit above my level of knowledge but still understandable and cool.
 

AsHkERE

RAM
Пользователь
Регистрация
06.04.2019
Сообщения
147
Реакции
46
Баллы
26
Telegram
Jabber
Верх