В ответ на прибыльный рост исследований уязвимостей, уровень интереса к двоичному сравнению пропатченных уязвимостей продолжает расти. Обнаруженные в частном порядке и обнаруженные внутри компании уязвимости обычно предоставляют ограниченные технические сведения. Процесс бинарного сравнения можно сравнить с охотой за сокровищами, когда исследователям предоставляется ограниченная информация о местонахождении и деталях уязвимости или "cхороненного сокровища". При наличии необходимых навыков и инструментов исследователь может найти и идентифицировать изменения кода, а затем разработать работающий эксплоит.
В этой главе мы рассмотрим следующие темы:
Введение в двоичное сравнение
При внесении изменений в скомпилированный код, такой как библиотеки, приложения и драйверы, разница между пропатченными и непропатченными версиями может дать возможность обнаружить уязвимости. На самом базовом уровне двоичное сравнение - это процесс выявления различий между двумя версиями одного и того же файла, такими как версия 1.2 и 1.3. Возможно, наиболее распространенной целью двоичных сравнений являются исправления Microsoft; однако это можно применить ко многим различным типам скомпилированного кода. Доступны различные инструменты для упрощения процесса сравнения двоичных файлов, что позволяет быстро определять изменения кода в дизассемблере.
Сравнение приложений
Обычно выпускаются новые версии приложений. Причина выпуска может включать в себя введение новых функций, изменения кода для поддержки новых платформ или версий ядра, использование новых средств контроля безопасности во время компиляции, таких как canaries или Control Flow Guard (CFG), а также исправление уязвимостей. Часто новая версия может включать комбинацию вышеупомянутых рассуждений. Чем больше изменений в коде приложения, тем сложнее выявить пропатченные уязвимости. Большая часть успеха в выявлении изменений кода, связанных с исправлениями уязвимостей, зависит от ограниченного раскрытия информации. Многие организации предпочитают публиковать минимальную информацию о характере исправления безопасности. Чем больше улик мы сможем получить из этой информации, тем больше вероятность, что мы обнаружим уязвимость. Эти типы подсказок будут показаны в реальных сценариях позже в этой главе.
Здесь показан простой пример фрагмента кода C, который включает уязвимость:
А здесь пропатченный код
Проблема с первым фрагментом заключается в использовании функции gets(), которая не предлагает проверки границ, что приводит к возможности переполнения буфера. В пропатченном коде используется функция fgets(), которая требует аргумента размера, что помогает предотвратить переполнение буфера. Функция fgets() считается устаревшей и, вероятно, это не лучший выбор из-за ее неспособности правильно обрабатывать нулевые байты, например, в двоичных данных; однако это лучший выбор, чем gets(). Мы рассмотрим этот простой пример позже, используя инструмент двоичного сравнения.
Сравнение патчей
Исправления безопасности, например, от Microsoft и Oracle, являются одними из самых прибыльных целей для двоичного сравнения. У Microsoft исторически был хорошо спланированный процесс управления исправлениями, который следует ежемесячному графику, при котором исправления выпускаются во второй вторник каждого месяца. Исправленные файлы чаще всего представляют собой библиотеки динамической компоновки (DLL) и файлы драйверов, хотя многие другие типы файлов также получают обновления. Многие организации не устанавливают исправления для своих систем быстро, оставляя открытой возможность для злоумышленников и специалистов на проникновение скомпрометировать эти системы с помощью публично раскрытых или разработанных в частном порядке эксплоитов с помощью различения исправлений. Начиная с Windows 10, Microsoft гораздо более агрессивно относится к требованиям к установке исправлений. В зависимости от сложности исправленной уязвимости и сложности поиска соответствующего кода рабочий эксплоит иногда может быть разработан быстро в первые дни после выпуска исправления. Эксплоиты, разработанные после обратного проектирования исправлений безопасности, обычно называют 1-day эксплоитами.
По мере продвижения по этой главе вы быстро увидите преимущества сравнения изменений кода для драйверов, библиотек и приложений. Хотя это и не новая дисциплина, двоичное сравнение только продолжает привлекать внимание исследователей безопасности, хакеров и производителей как жизнеспособный метод обнаружения уязвимостей и получения прибыли. Ценник на 1-day эксплойт не так высок, как 0-day; однако нередки случаи, когда выплаты за столь востребованные эксплоиты выражаются пятизначными числами. Поставщики фреймворков для эксплуатации хотят иметь больше эксплоитов, связанных с уязвимостями, раскрытыми в частном порядке, чем их конкуренты.
Инструменты двоичного сравнения
Ручной анализ скомпилированного кода больших двоичных файлов с помощью дизассемблеров, таких как Interactive Disassembler (IDA), может стать сложной задачей даже для самого опытного исследователя. Благодаря использованию свободно доступных и коммерчески доступных инструментов сравнения двоичных файлов можно упростить процесс определения интересующего кода, связанного с исправленной уязвимостью. Такие инструменты могут сэкономить сотни часов времени, потраченного на реверс кода, который может не иметь отношения к искомой уязвимости. Вот пять наиболее широко известных инструментов для сравнения двоичных файлов:
Каждый из этих инструментов работает как подключаемый модуль к IDA, используя различные методы и эвристики для определения изменений кода между двумя версиями одного и того же файла. Вы можете получить разные результаты при использовании каждого инструмента с одними и теми же входными файлами. Для каждого из инструментов требуется возможность доступа к файлам базы данных IDA (.idb), следовательно, требуется лицензионная версия IDA или бесплатная версия с turbodiff. Для примеров в этой главе мы будем использовать коммерческий инструмент BinDiff, а также turbodiff, потому что он работает с бесплатной версией IDA 5.0, которую все еще можно найти в Интернете на различных сайтах. Это позволяет пользователям, не имеющим коммерческой версии IDA, выполнять упражнения. Единственные инструменты из списка, которые активно поддерживаются, - это Diaphora и BinDiff, хотя BinDiff не часто обновляется. Авторы каждого из них заслуживают высокой оценки за предоставление таких прекрасных инструментов, которые экономят нам бесчисленные часы, пытаясь найти изменения в коде.
BinDiff
Как упоминалось ранее, в начале 2011 года Google приобрела немецкую компанию по разработке программного обеспечения Zynamics, которую возглавлял известный исследователь Thomas Dullien, также известный как Halvar Flake. Zynamics была широко известна инструментами BinDiff и BinNavi, которые помогают в реверс инжиниринге. После приобретения Google значительно снизил стоимость этих инструментов до одной десятой их первоначальной цены, что сделало их гораздо более доступными. В марте 2016 года Google объявил, что в будущем BinDiff будет бесплатным. Новые версии обычно не выпускаются, при этом BinDiff 4.3 был самой последней версией на момент написания этой статьи. Версия 4.3 предлагает поддержку macOS. BinDiff часто называют одним из лучших инструментов в своем роде, обеспечивающим глубокий анализ изменений блоков и кода. По состоянию на начало 2018 года BinDiff не был портирован для работы с IDA 7.1 или более поздней версии. Это может измениться в любой момент.
BinDiff 4.3 поставляется в виде пакета установщика Windows (.msi). Для установки требуется всего несколько щелчков мышью, лицензионная копия IDA и Java SE Runtime Environment 8. Чтобы использовать BinDiff, вы должны разрешить IDA выполнять автоматический анализ двух файлов, которые вы хотите сравнить, и сохранить файлы IDB. Когда это будет завершено и один из файлов будет открыт внутри IDA, вы нажмете CTRL+6, чтобы вызвать графический интерфейс BinDiff, как показано здесь.
Следующим шагом является нажатие кнопки Diff Database и выбор другого файла IDB для сравнения. В зависимости от размера файлов это может занять минуту или две. После завершения сравнения в IDA появятся новые вкладки, включая "Matched Functions", "Primary Unmatched" и "Secondary Unmatched". Вкладка "Matched Functions" содержит функции, существующие в обоих файлах, которые могут включать или не включать изменения. Другую вкладку можно закрыть. Каждая функция получает оценку от 0 до 1,0 в столбце Similarity, как показано ниже. Чем ниже значение, тем больше изменилась функция между двумя файлами. Как заявляет Zynamics/Google в отношении вкладок Primary Unmatched и Secondary Unmatched, "Первая отображает функции, которые содержатся в текущей открытой базе данных и не связаны ни с одной функцией из различаемой базы данных, тогда как Secondary Unmatched subview содержит функции которые находятся в базе данных diff, но не связаны ни с какими функциями в первой".
Для получения наиболее точных результатов важно различать правильные версии файла. При переходе на сайт Microsoft TechNet для приобретения исправлений, опубликованных до апреля 2017 г., вы увидите столбец справа под названием "Updates Replaced". Вскоре будет рассмотрен процесс получения исправлений, начавшийся в апреле 2017 года. Щелкнув ссылку в этом месте и это приведет вас к предыдущему самому последнему обновлению исправляемого файла. Такой файл, как mshtml.dll, обновляется почти каждый месяц. Если вы сравниваете версию файла, полученную несколькими месяцами ранее, с только что выпущенным патчем, количество различий между двумя файлами очень затруднит анализ. Другие файлы не исправляются очень часто, поэтому, щелкнув вышеупомянутую ссылку, вы перейдете к последнему обновлению файла, о котором идет речь, чтобы вы могли различать подходящие версии. После того, как интересующая функция идентифицирована с помощью BinDiff, визуальное сравнение может быть сгенерировано либо щелчком правой кнопкой мыши по желаемой функции на вкладке "Matched Functions" и выбором "View Flowgraphs", либо щелчком по желаемой функции и нажатием CTRL+E. Ниже приведен пример визуального сравнения. Обратите внимание, что вы не сможете прочитать дисассемблерный код, потому что он уменьшен, чтобы поместиться на странице.
Turbodiff
Другой инструмент, который мы рассмотрим в этой главе, - turbodiff. Этот инструмент был выбран из-за его способности работать с бесплатной версией IDA 5.0. DarunGrim и patchdiff2 также являются отличными инструментами; однако для их использования требуется лицензионная копия IDA, что делает невозможным выполнение упражнений в этой главе без приобретения лицензионной копии для тех, кто читает ее. DarunGrim и patchdiff2 удобны для пользователя и просты в установке с помощью IDA. Diaphora - еще одна фантастическая альтернатива BinDiff, и вам предлагается попробовать ее и сравнить это в BinDiff.
Как упоминалось ранее, плагин turbodiff можно получить с веб-сайта http://corelabs.coresecurity.com/, и его можно бесплатно загрузить и использовать по лицензии GPLv2. Последний стабильный выпуск - версия 1.01b_r2, выпущенный 19 декабря 2011 года. Чтобы использовать turbodiff, вы должны загрузить два файла для сравнения по одному в IDA. После того, как IDA завершит свой автоматический анализ первого файла, вы нажмете CTRL+F11, чтобы открыть всплывающее меню turbodiff. Из вариантов при первом анализе файла выберите "take info from this idb" и нажмите "ОК". Повторите те же шаги для другого файла, который нужно включить в diff. Как только это будет выполнено с обоими файлами, которые нужно сравнить, снова нажмите CTRL+F11, выберите вариант "compare with…", а затем выберите другой файл IDB. Должно появиться следующее окно.
В столбце категории вы можете увидеть такие ярлыки, как идентичный, подозрительный+, подозрительный++ и измененный. Каждая метка имеет значение и может помочь исследователю выделить наиболее интересные функции, в первую очередь метки подозрительный+ и подозрительный++. Эти метки указывают на то, что были обнаружены контрольные суммы в одном или нескольких блоках выбранной функции, а также на то, изменилось ли количество инструкций. Когда вы дважды щелкаете имя нужной функции, отображается визуальное сравнение, при этом каждая функция отображается в своем собственном окне, как показано здесь.
Лабораторная работа 17-1. Наше первое сравнение.
В этой лабораторной работе вы выполните простое сравнение с кодом, ранее показанным в разделе "Application Diffing". Необходимо сравнить двоичные файлы ELF name и name2. Имя файла - это файл без исправлений, а name2 - с исправлением. Сначала необходимо запустить IDA 5.0, которое вы установили ранее. Как только она будет запущена, перейдите в File | New, выберите вкладку Unix во всплывающем окне и щелкните параметр ELF слева, как показано здесь, а затем щелкните OK.
Перейдите в папку C:\grayhat\app_diff\ и выберите файл name. Примите появившиеся параметры по умолчанию. IDA должна быстро завершить свой автоматический анализ, используя по умолчанию функцию main() в окне дизассемблирования, как показано ниже.
Нажмите CTRL+F11, чтобы открыть всплывающее окно turbodiff. Если он не появляется, вернитесь назад и убедитесь, что вы правильно скопировали необходимые файлы для turbodiff. С окном turbodiff на экране выберите опцию "take info from this idb" и нажмите OK, а затем еще раз "OK". Затем перейдите в File | New, и вы получите всплывающее окно с вопросом, хотите ли вы сохранить базу данных. Примите значения по умолчанию и нажмите "ОК". Повторите шаги выбора вкладки Unix | ELF Executable, а затем нажмите OK. Откройте двоичный файл ELF name2 и примите значения по умолчанию. Повторите шаги по открытию всплывающего окна turbodiff.
Теперь, когда вы выполнили это для обоих файлов, снова нажмите CTRL+F11, при этом файл name2 все еще открыт в IDA. Выберите вариант "compare with…" и нажмите "ОК". Выберите файл name.idb и нажмите "ОК", а затем — "ОК". Должно появиться следующее поле (возможно, вам придется отсортировать по категориям, чтобы воспроизвести точное изображение).
Обратите внимание, что функция getName() помечена как "подозрительная++". Дважды щелкните функцию getName(), чтобы открыть следующее окно.
На этом изображении в левом окне показана пропатченная функция, а в правом окне - непропатченная функция. Блок без исправлений использует функцию gets(), которая не обеспечивает проверку границ. Исправленный блок использует функцию fgets(), для которой требуется аргумент размера, чтобы предотвратить переполнение буфера. Пропатченный дизассемблерный код показан здесь:
Внутри этих двух функций была пара дополнительных блоков кода, но они белые и не содержат измененного кода. Это просто код защиты стека, который проверяет canaries стека, за которым следует эпилог функции. На этом лабораторная работа завершена. В дальнейшем мы посмотрим на real-world различия.
Процесс управления патчами
У каждого поставщика есть собственный процесс распространения исправлений, включая Oracle, Microsoft и Apple. У некоторых поставщиков есть установленное расписание выпуска исправлений, тогда как у других нет установленного расписания. Наличие постоянного цикла выпуска исправлений, например, используемого Microsoft, позволяет ответственным за управление большим количеством систем соответствующим образом планировать обновление. Внеполосные исправления могут быть проблематичными для организаций, потому что могут не быть доступных ресурсов для развертывания обновлений. Мы сосредоточимся в первую очередь на процессе управления исправлениями Microsoft, потому что это зрелый процесс, который часто используется для обнаружения уязвимостей с целью извлечения прибыли.
Microsoft Patch Tuesday
Второй вторник каждого месяца - это ежемесячный цикл исправлений Microsoft, иногда с выходом дополнительных исправлений из-за критического обновления. Процесс менялся с момента появления накопительных обновлений Windows 10, вступающих в силу в Windows 7 и 8 с октября 2016 года, а также изменения способа загрузки исправлений. Вплоть до апреля 2017 г. сводку и исправления безопасности для каждого обновления можно было найти по адресу https://technet.microsoft.com/en-us/security/bulletin. Начиная с апреля 2017 г., исправления можно получить на сайте Microsoft Security TechCenter по адресу https://portal.msrc.microsoft.com/en-us/security-guidance, а сводную информацию можно найти на сайте https://portal.msrc.microsoft.com/en-us/security-guidance/summary. Исправления обычно получаются с помощью инструмента Windows Update на панели управления Windows или управляются централизованно с помощью такого продукта, как Windows Server Update Services (WSUS) или Windows Update для бизнеса (WUB). Если исправления необходимы для распространения, их можно получить по вышеупомянутой ссылке TechNet.
Каждый бюллетень исправлений связан с дополнительной информацией об обновлении. Некоторые обновления являются результатом публично обнаруженной уязвимости, в то время как большинство из них связано с той или иной формой скоординированного частного раскрытия информации. На следующем изображении показан пример одной такой уязвимости, раскрытой в частном порядке.
Как видите, об уязвимости предоставляется лишь ограниченная информация. Чем больше информации предоставлено, тем больше вероятность, что кто-то сможет быстро найти исправленный код и создать работающий эксплоит. В зависимости от размера обновления и сложности уязвимости обнаружение только исправленного кода может оказаться сложной задачей. Часто уязвимое состояние носит чисто теоретический характер или может возникать только при очень специфических условиях. Это может увеличить сложность определения основной причины и создания POC, который успешно запускает ошибку. Как только основная причина определена и уязвимый код найден и доступен для анализа в отладчике, необходимо определить, насколько сложно будет добиться выполнения кода, если это применимо.
Получение и извлечение исправлений Microsoft
Скоро мы дойдем до лабораторной, но сначала давайте рассмотрим пример получения и извлечения накопительного обновления для Windows 10. Накопительные обновления до апреля 2017 г. доступны в Microsoft TechNet по адресу https://technet.microsoft.com/en-us/library/security/dn631937.aspx. Накопительные обновления с апреля 2017 г. доступны по адресу https://portal.msrc.microsoft.com/en-us/security-guidance. В нашем примере мы смотрим на MS17-010, в котором исправлено несколько ошибок с SMB и который был выпущен в марте 2017 года. Информация об этом раскрытии доступна по адресу https://technet.microsoft.com/en-us/library/security/ms17-010.aspx. Заголовки исправлений безопасности показаны на следующем изображении.
Мы сосредоточимся на CVE-2017-0147, "Уязвимость Windows SMB, связанная с раскрытием информации", чтобы просто определить исправление, но сначала мы должны загрузить и извлечь обновление. Используя вышеупомянутую ссылку на MS17-010, щелкните и загрузите 32-разрядное обновление Windows 10 через сервер каталогов Microsoft, как показано ниже.
Обведенная область слева - это ссылка для загрузки обновления через сервер каталога. Обведенная ссылка справа - это поле Updates Replaced. Щелкнув по этой ссылке, вы перейдете к информации об обновлении, когда в последний раз были исправлены соответствующий файл или файлы. Если файл srv.sys был исправлен в октябре 2017 года, а последний раз он был исправлен до этого в июле 2017 года, ссылка Updates Replaced приведет вас к этому обновлению. Это важно отметить, потому что вы всегда хотите различать версии, наиболее близкие друг к другу, чтобы любые изменения функций были связаны с интересующими вас CVE.
Теперь, когда было загружено накопительное обновление для 32-разрядной версии Windows 10 за март 2017 г., мы будем использовать инструмент PatchExtract, созданный Greg Linares, чтобы упростить извлечение. PatchExtract - это сценарий PowerShell, который использует Microsoft инструмент expand и другие команды для извлечения и упорядочивания множества файлов, содержащихся в загруженном файле MSU и последующих файлах CAB. На момент написания этой статьи PatchExtract версии 1.3 все еще оставался самой последней. Он доступен по адресу https://pastebin.com/VjwNV23n. Greg пользуется псевдонимом Twitter @Laughing_Mantis. Также существует связанный сценарий PowerShell под названием PatchClean, который помогает в дальнейшей организации извлеченных обновлений и гарантирует, что только файлы, которые были изменены в течение последних 30 дней, помечены как интересные. Причина в том, что накопительные обновления содержат все обновления, относящиеся к этой версии Windows, за многие месяцы. PatchClean перемещает все файлы старше 30 дней в "старую" папку, чтобы можно было уделить внимание недавно обновленным файлам. Это по-прежнему требует, чтобы вы выполнили проверку, и вы также должны знать дату, когда выполняется извлечение. Если вы выполняете извлечение и запускаете PatchClean после даты выпуска первоначального исправления, вам может потребоваться соответствующая настройка даты и времени.
Следующая команда является примером запуска PatchExtract из командной строки администратора для извлечения файлов и исправлений из накопительного обновления за март 2017 года:
Команда может выглядеть длинной, но в основном это связано с введенным путем и длинным именем кумулятивного обновления. После ввода PatchExtract выполнит извлечение, что может занять несколько минут в зависимости от размера файла. Накопительные обновления Windows 10 x64 могут иметь размер более 1 ГБ, поэтому мы выбрали версию x86. Как только оно будет закончено, у нас останется несколько папок. В нашем примере мы хотим зайти в папку "x86" и посмотреть что внутри. Там есть 1165 вложенных папок. Найдите минутку, чтобы подумать о нашей цели. Мы хотим идентифицировать только файлы, относящиеся к мартовскому циклу исправлений 2017 года, но у нас осталось 1165 подпапок. Здесь в игру вступает инструмент PatchClean. Сначала мы хотим зайти и изменить дату системы, используемой для анализа, на дату вторника исправлений для марта 2017 года. Это будет вторник, 14 марта. По умолчанию PatchClean возвращается на 30 дней назад с даты и перемещает все файлы, время изменения которых превышает указанное, в "старую" папку. Это позволяет нам видеть, какие файлы были изменены за последние 30 дней.
После завершения скрипта у нас остается 318 из 1165 исходных папок. Это большое количество неудивительно, поскольку Microsoft пропустила вторник исправлений в феврале 2017 года из-за задержек с исправлением уязвимостей SMB.
Лабораторная 17-2: Diffing MS17-010
В этой лабораторной работе вы будете использовать два файла srv.sys, доступные в репозитории Gray Hat. Один находится в папке "Old", а другой - в папке "New". Новый из обновления за март 2017 года. Примеры, показанные в этой лабораторной работе, взяты из IDA 7.0 в режиме совместимости с x86 для использования подключаемого модуля BinDiff 4.3.
Первый шаг - открыть вашу лицензионную копию IDA или бесплатную версию 5.0, если у вас нет лицензионной версии, и открыть новый файл srv.sys. Разрешите IDA завершить анализ. По завершении сохраните базу данных и откройте старую версию srv.sys. После завершения анализа вы готовы к выполнению сравнения. Загрузив cтарый файл srv.sys, нажмите CTRL+6, чтобы открыть меню BinDiff, а затем щелкните Diff Database .… Если вы используете turbodiff, нажмите CTRL+F11, чтобы вызвать его меню, и используйте тот же метод, что и в лабораторной работе 17-1.
После нажатия кнопки Diff Database… перейдите к IDB-файлу «New» srv.sys и выполните сравнение. Через несколько секунд сравнение должно быть завершено, и у вас должны появиться новые вкладки внутри IDA. То, что нас интересует, - это "Matched Functions". В результатах сравнения, показанных ниже, мы выбрали функцию SrvSmbTransaction(). Часто, когда есть более чем несколько функций с изменениями, вы должны смотреть на имена функций при определении потенциальных интересующих функций.
Нажмите CTRL+E, чтобы выполнить графическое сравнение. При использовании turbodiff обязательно используйте метод, описанный ранее, для графического сравнения. Вот "уменьшенный" обзор графического сравнения.
Если вы щелкнете по любому из ассемблерных блоков, а не просто увеличите масштаб, экран изменит конфигурацию и отобразит только группу вокруг выбранного блока. Если вы хотите вернуться к основному обзору, вы должны щелкнуть значок "Select Ancestors" на главной панели ленты BinDiff, как показано ниже.
В этом примере непропатченная версия srv.sys находится слева, а пропатченная версия - справа. После увеличения и осмотра различий мы обнаруживаем интересное изменение. Следующее изображение взято из непропатченной версии, и вы можете видеть, что функция ExecuteTransaction вызывается, как указано.
Теперь посмотрим на пропатченную версию. Тот же самый блок кода, который приводит к вызову функции ExecuteTransaction, теперь вместо этого сначала выполняет некоторые вызовы функции memset.
Вы все еще можете видеть функцию ExecuteTransaction в среднем блоке, но поток должен сначала пройти через вызовы функции memset, прежде чем попасть в этот блок. Не стесняйтесь следовать за парой блоков на этом пути. Вызов функции memset, вероятно, устраняет утечку информации, связанную с CVE-2017-0147.
Сравнение патча для эксплуатации
В предыдущем сравнении патчей Microsoft с MS17-010 мы выявили изменения кода, которые разрешили проблему раскрытия информации; однако это не привело нас к эксплуатации ошибки. В следующем примере мы рассмотрим ошибку загрузки DLL, которая может позволить разрешить удаленное выполнение кода и запустить работающий эксплойт. И MS16-009, и MS16-014 заявляют о решении CVE-2016-0041, которая связана с "DLL Loading Remote Code Execution Vulnerability". Автор обнаружил, что интересующий нас файл был доступен в MS16-009 патче.
Чтобы оставаться последовательным, ошибка была обнаружена Greg Linares, который написал ранее описанный инструмент PatchExtract.
DLL Side-Loading Bugs
При проверке в Интернете вы можете получить различные определения того, что представляет собой DLL side-loading bug. В зависимости от настроек в реестре, а также аргументов, переданных функции загрузки DLL, такой как набор функций LoadLibrary(), может быть один или несколько способов принудительной загрузки нежелательной DLL. Давайте воспользуемся простой аналогией, чтобы описать пример проблемы. Мы предполагаем, что вы всегда кладете соль и перец, используемые в еде, в определенное место на кухне. Представьте, что в следующий раз, когда вы воспользуетесь ими, их нет в этом месте. Вы можете отказаться от соли и перца или искать их в других местах, например, в других шкафах, столах и прилавках.
В конце концов, вы либо найдете соль и перец, либо откажетесь. Это не так уж отличается от порядка поиска, используемого при загрузке DLL. Более безопасный параметр - разрешить загрузку желаемой DLL только из очень определенного места, например C:\Windows\System32\.
Менее безопасный вариант - разрешить загрузку DLL из разных мест на основе приоритета порядка поиска.
Давайте подробнее рассмотрим, как и откуда можно загружать библиотеки DLL. Во-первых, в последних нескольких версиях Windows есть контейнер реестра, обычно в HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SessionManager\KnownDLLs\.
Здесь показан пример.
В этом контейнере хранятся библиотеки DLL, которые обычно используются для ускорения загрузки программ, но некоторые также рассматривают его как средство контроля безопасности, поскольку он указывает, что перечисленные библиотеки DLL могут быть загружены только из папки System32 в C:\Windows\System32\ или C:\Windows\SysWOW64\. Затем функцию LoadLibraryEx можно использовать для динамической загрузки библиотек DLL, запрошенных процессом:
Одним из обязательных аргументов является dwFlags, который используется для указания того, откуда потенциально может быть загружена DLL, и других вариантов поведения, например, связанных с AppLocker, и того, что произойдет при входе в отношении выполнения кода.
Дополнительную информацию можно найти на https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx. Если для аргумента dwFlags оставить значение по умолчанию 0, поведение будет таким же, как у более старой функции LoadLibrary, которая реализует SafeDllSearchMode. Как заявляет Microsoft:
"Если включен SafeDllSearchMode, порядок поиска будет следующим:
- Каталог, из которого загружено приложение.
- Системный каталог. Используйте функцию GetSystemDirectory, чтобы получить путь к этому каталогу.
- 16-битный системный каталог. Нет функции, которая получает путь к этому каталогу, но он ищется.
- Каталог Windows. Используйте функцию GetWindowsDirectory, чтобы получить путь к этому каталогу.
- Текущий каталог.
- Каталоги, перечисленные в переменной среды PATH.
Обратите внимание, что это не включает путь для каждого приложения, указанный в разделе реестра App Paths. Ключ App Paths не используется при вычислении пути поиска DLL ".
Из этих вариантов 5 и 6 потенциально представляют угрозу безопасности, поскольку они могут включать в себя местоположения, на которые может повлиять злоумышленник, например местоположения, доступные для записи всем. Обычная опция dwFlags, используемая для защиты вызовов LoadLibraryEX, - это 0x800 LOAD_LIBRARY_SEARCH_SYSTEM32. Этот параметр ограничивает загрузку библиотеки DLL только папкой System32.
Лабораторная 17-3: Diffing MS16-009
В этой лабораторной работе мы анализируем исправление безопасности, связанное с MS16-009 и MS16-014, которые оба утверждают, что устраняют CVE-2016-0041. Процесс извлечения патча завершен за вас и доступен в репозитории кода Gray Hat. В показанных примерах различий патчей используются IDA 7.0 x64 и BinDiff 4.3. Операционные системы, задействованные в эксплуатации, - это Kali Linux x64 и Windows 10 x64 Home Edition, номер сборки 10586. Версия Skype, используемая в базовой сборке Windows 10 — 7.18.0.112.
При извлечении патча MS16-009 мы определили, что файл urlmon.dll был обновлен. Как обновленная версия urlmon.dll, так и предыдущая были предоставлены вам в рамках этой лабораторной работы. Первый шаг - дизассемблировать их с помощью IDA и выполнить сравнение. Вы должны использовать BinDiff 4.3 с IDA, который поддерживает дизассемблирование 64-битных входных файлов, поскольку эта ошибка затрагивала только 64-битную Windows. Если у вас нет возможности дизассемблировать 64-разрядные входные файлы и сохранить файлы базы данных IDA .idb, вы не сможете выполнить эту лабораторную работу, а вместо этого сможете только прочитать следующие разделы. Вы также можете изучить radare2 как альтернативу IDA.
Теперь выполните сравнение, используя одну из этих опций. На следующем изображении показаны результаты при использовании BinDiff.
Согласно BinDiff изменилась только одна функция. Нет ничего проще, чем дать нам возможность сосредоточиться на функции, связанной с исправлением ошибки. Имя функции — BuildUserAgentStringMobileHelper(). Давайте нажмем CTRL+E, чтобы выполнить графическое сравнение. На следующем изображении показаны общие результаты.
При увеличении масштаба изменений кода мы можем быстро идентифицировать следующий блок.
Вы должны сразу заметить, что в непропатченной версии слева аргумент dwFlags подвергается операции XOR с 0. Это заставит SafeDllSearchMode вступить в силу. В исправленной версии справа для dwFlags установлено значение 0x800, что ограничит загрузку желаемой DLL в папку System32. Мы хотим увидеть, какая DLL загружается в это место в коде. Для этого мы можем просто вернуться в IDA и перейти к функции BuildUserAgentStringMobileHelper(). Самый простой способ быстро туда добраться - просто щелкнуть окно функций в IDA и начать вводить желаемое имя функции. Затем дважды щелкните по нему, чтобы вызвать дизассемблирование. Вы также можете пропустите этот шаг, щелкнув в главном окне дизассемблирования IDA, нажав G и введя адрес, куда вы хотите перейти. Оглядываясь назад на непропатченные результаты в BinDiff, мы видим, что интересующий адрес — 0x18003BCB1. После перехода по этому адресу мы получаем желаемый результат, как показано ниже.
Как видите, в этот момент кода загружается DLL-библиотека phoneinfo.dll. Вы можете пропустить следующий шаг, но цель состоит в том, чтобы показать вам, как определить, какие приложения нуждаются в этой DLL. Во-первых, в корне файловой системы был выполнен исчерпывающий поиск, чтобы увидеть, существует ли файл phoneinfo.dll в базовой установке Windows 10 x64. Было подтверждено, что файл не существует. Затем мы хотим запустить инструмент Process Monitor от Microsoft (доступный по адресу https://docs.microsoft.com/en-us/sysinternals/downloads/procmon). На следующем изображении показаны два фильтра, примененные к инструменту Process Monitor после его запуска.
Первый фильтр вступает в силу, если "Результат" - "NAME NOT FOUND". Второй фильтр предназначен для «Пути» и заканчивается на "phoneinfo.dll". После применения этих фильтров мы запускаем различные приложения, такие как IE11, Edge, Skype, OneDrive, Word и другие.
Поскольку DLL называется phoneinfo.dll, имеет смысл попробовать определенные приложения на основе только имени. Ниже приводится пример результатов.
Вы можете видеть, что и Internet Explorer, и Skype пытаются загрузить DLL. Справа вы можете увидеть все отмеченные места. Это поведение SafeDllSearchMode. Примечательно, что мы видим, что C:\Python27\ является одним из местоположений проверки. Если мы сможем создать вредоносную DLL с помощью msfvenom, используя Meterpreter в качестве полезной нагрузки, мы сможем получить удаленный сеанс с уязвимой системой Windows 10. На следующем изображении показано создание вредоносного файла phoneinfo.dll, который содержит полезную нагрузку Meterpreter, которая подключается к нашей системе Kali Linux. Сразу после этого мы используем модуль Python SimpleHTTPServer для передачи вредоносной DLL системе-жертве. Мы не применяли никаких методов кодирования обхода антивируса (AV), или других методов, поэтому мы отключили Защитник Windows, чтобы протестировать эксплойт.
Затем мы запускаем прослушиватель Metasploit для получения входящего соединения в случае успеха нашей атаки.
Когда слушатели Python и Metasploit работают, мы возвращаемся в систему Windows и используем Internet Explorer для подключения к системе Kali через порт 8080. Затем мы загружаем файл phoneinfo.dll и сохраняем его в C:\Python27\, как показано здесь.
Затем мы запускаем Skype, который должен загрузить вредоносную DLL из папки C:\Python27\ как часть операции SafeDllSearchMode, как показано ниже.
Когда приложение Skype запущено, мы снова переключаемся на Kali Linux, чтобы увидеть, установлен ли сеанс Meterpreter.
Успех! Если мы хотим проделать это в условиях дикой среды, нужно учесть несколько вещей. Во-первых, мы, безусловно, хотели бы закодировать полезную нагрузку таким образом, чтобы избежать обнаружения AV. Во-вторых, мы хотели бы найти способ обманом заставить жертву загрузить вредоносную DLL в свою систему в определенное место. Это можно сделать с помощью фишинга. Заставить жертву думать, что существует критическое обновление Skype и что DLL необходимо разместить в определенном месте.
Резюме
В этой главе были представлены двоичное сравнение и различные инструменты, которые помогут ускорить анализ. Мы рассмотрели простой пример, подтверждающий концепцию приложения, а затем изучили реальные исправления, чтобы определить уязвимости и проверить наши предположения. Это приобретенный навык, тесно связанный с вашим опытом отладки и чтения дизассемблированного кода. Чем чаще вы это делаете, тем лучше вы будете определять изменения кода и потенциальные исправленные уязвимости. Microsoft прекратила поддержку Windows XP и Vista; однако некоторые версии, например с XP Embedded, все еще поддерживаются и получают исправления. Это может дать возможность продолжить анализ исправлений в операционной системе, которая не имеет такой сложности. Microsoft также нередко незаметно вносит изменения в код с помощью другого патча. Иногда это отличается в разных версиях Windows, где одна версия Windows может предоставить больше информации, чем различие другой версии.
Источник: Gray Hat Hacking the Ethica Hacker's Handbook 5th
Автор перевода: yashechka
Переведено специально для портала xss.pro (c)
В этой главе мы рассмотрим следующие темы:
- Сравнения приложений и патчей
- Инструменты для двоичного сравнения
- Процесс управления патчами
- Real-world сравнения
Введение в двоичное сравнение
При внесении изменений в скомпилированный код, такой как библиотеки, приложения и драйверы, разница между пропатченными и непропатченными версиями может дать возможность обнаружить уязвимости. На самом базовом уровне двоичное сравнение - это процесс выявления различий между двумя версиями одного и того же файла, такими как версия 1.2 и 1.3. Возможно, наиболее распространенной целью двоичных сравнений являются исправления Microsoft; однако это можно применить ко многим различным типам скомпилированного кода. Доступны различные инструменты для упрощения процесса сравнения двоичных файлов, что позволяет быстро определять изменения кода в дизассемблере.
Сравнение приложений
Обычно выпускаются новые версии приложений. Причина выпуска может включать в себя введение новых функций, изменения кода для поддержки новых платформ или версий ядра, использование новых средств контроля безопасности во время компиляции, таких как canaries или Control Flow Guard (CFG), а также исправление уязвимостей. Часто новая версия может включать комбинацию вышеупомянутых рассуждений. Чем больше изменений в коде приложения, тем сложнее выявить пропатченные уязвимости. Большая часть успеха в выявлении изменений кода, связанных с исправлениями уязвимостей, зависит от ограниченного раскрытия информации. Многие организации предпочитают публиковать минимальную информацию о характере исправления безопасности. Чем больше улик мы сможем получить из этой информации, тем больше вероятность, что мы обнаружим уязвимость. Эти типы подсказок будут показаны в реальных сценариях позже в этой главе.
Здесь показан простой пример фрагмента кода C, который включает уязвимость:
А здесь пропатченный код
Проблема с первым фрагментом заключается в использовании функции gets(), которая не предлагает проверки границ, что приводит к возможности переполнения буфера. В пропатченном коде используется функция fgets(), которая требует аргумента размера, что помогает предотвратить переполнение буфера. Функция fgets() считается устаревшей и, вероятно, это не лучший выбор из-за ее неспособности правильно обрабатывать нулевые байты, например, в двоичных данных; однако это лучший выбор, чем gets(). Мы рассмотрим этот простой пример позже, используя инструмент двоичного сравнения.
Сравнение патчей
Исправления безопасности, например, от Microsoft и Oracle, являются одними из самых прибыльных целей для двоичного сравнения. У Microsoft исторически был хорошо спланированный процесс управления исправлениями, который следует ежемесячному графику, при котором исправления выпускаются во второй вторник каждого месяца. Исправленные файлы чаще всего представляют собой библиотеки динамической компоновки (DLL) и файлы драйверов, хотя многие другие типы файлов также получают обновления. Многие организации не устанавливают исправления для своих систем быстро, оставляя открытой возможность для злоумышленников и специалистов на проникновение скомпрометировать эти системы с помощью публично раскрытых или разработанных в частном порядке эксплоитов с помощью различения исправлений. Начиная с Windows 10, Microsoft гораздо более агрессивно относится к требованиям к установке исправлений. В зависимости от сложности исправленной уязвимости и сложности поиска соответствующего кода рабочий эксплоит иногда может быть разработан быстро в первые дни после выпуска исправления. Эксплоиты, разработанные после обратного проектирования исправлений безопасности, обычно называют 1-day эксплоитами.
По мере продвижения по этой главе вы быстро увидите преимущества сравнения изменений кода для драйверов, библиотек и приложений. Хотя это и не новая дисциплина, двоичное сравнение только продолжает привлекать внимание исследователей безопасности, хакеров и производителей как жизнеспособный метод обнаружения уязвимостей и получения прибыли. Ценник на 1-day эксплойт не так высок, как 0-day; однако нередки случаи, когда выплаты за столь востребованные эксплоиты выражаются пятизначными числами. Поставщики фреймворков для эксплуатации хотят иметь больше эксплоитов, связанных с уязвимостями, раскрытыми в частном порядке, чем их конкуренты.
Инструменты двоичного сравнения
Ручной анализ скомпилированного кода больших двоичных файлов с помощью дизассемблеров, таких как Interactive Disassembler (IDA), может стать сложной задачей даже для самого опытного исследователя. Благодаря использованию свободно доступных и коммерчески доступных инструментов сравнения двоичных файлов можно упростить процесс определения интересующего кода, связанного с исправленной уязвимостью. Такие инструменты могут сэкономить сотни часов времени, потраченного на реверс кода, который может не иметь отношения к искомой уязвимости. Вот пять наиболее широко известных инструментов для сравнения двоичных файлов:
- Zynamics BinDiff (free). Приобретенный Google в начале 2011 года, Zynamics BinDiff доступен по адресу www.zynamics.com/bindiff.html. Требуется лицензионная версия IDA версии 5.5 или новее.
turbodiff (free). Разработанный Nicolas Economou из Core Security, turbodiff доступен по адресу http://corelabs.coresecurity.com/index.php?module=Wiki&action=view&type=tool&name=turbodiff. Его можно использовать с бесплатной версией IDA 4.9 или 5.0.
- patchdiff2 (free). patchdiff2, разработанный Nicolas Pouvesle, доступен по адресу https://code.google.com/p/patchdiff2/. Требуется лицензионная версия IDA 6.1 или новее.
- DarunGrim (бесплатно), DarunGrim, разработанный Jeong Oh О (Matt Oh), доступен на www.darungrim.org. Требуется последняя лицензионная версия IDA.
- Diaphora (бесплатно) разработанный Joxean Koret. Diaphora доступна по адресу https://github.com/joxeankoret/diaphora. Официально поддерживаются только самые последние версии IDA.
Каждый из этих инструментов работает как подключаемый модуль к IDA, используя различные методы и эвристики для определения изменений кода между двумя версиями одного и того же файла. Вы можете получить разные результаты при использовании каждого инструмента с одними и теми же входными файлами. Для каждого из инструментов требуется возможность доступа к файлам базы данных IDA (.idb), следовательно, требуется лицензионная версия IDA или бесплатная версия с turbodiff. Для примеров в этой главе мы будем использовать коммерческий инструмент BinDiff, а также turbodiff, потому что он работает с бесплатной версией IDA 5.0, которую все еще можно найти в Интернете на различных сайтах. Это позволяет пользователям, не имеющим коммерческой версии IDA, выполнять упражнения. Единственные инструменты из списка, которые активно поддерживаются, - это Diaphora и BinDiff, хотя BinDiff не часто обновляется. Авторы каждого из них заслуживают высокой оценки за предоставление таких прекрасных инструментов, которые экономят нам бесчисленные часы, пытаясь найти изменения в коде.
BinDiff
Как упоминалось ранее, в начале 2011 года Google приобрела немецкую компанию по разработке программного обеспечения Zynamics, которую возглавлял известный исследователь Thomas Dullien, также известный как Halvar Flake. Zynamics была широко известна инструментами BinDiff и BinNavi, которые помогают в реверс инжиниринге. После приобретения Google значительно снизил стоимость этих инструментов до одной десятой их первоначальной цены, что сделало их гораздо более доступными. В марте 2016 года Google объявил, что в будущем BinDiff будет бесплатным. Новые версии обычно не выпускаются, при этом BinDiff 4.3 был самой последней версией на момент написания этой статьи. Версия 4.3 предлагает поддержку macOS. BinDiff часто называют одним из лучших инструментов в своем роде, обеспечивающим глубокий анализ изменений блоков и кода. По состоянию на начало 2018 года BinDiff не был портирован для работы с IDA 7.1 или более поздней версии. Это может измениться в любой момент.
BinDiff 4.3 поставляется в виде пакета установщика Windows (.msi). Для установки требуется всего несколько щелчков мышью, лицензионная копия IDA и Java SE Runtime Environment 8. Чтобы использовать BinDiff, вы должны разрешить IDA выполнять автоматический анализ двух файлов, которые вы хотите сравнить, и сохранить файлы IDB. Когда это будет завершено и один из файлов будет открыт внутри IDA, вы нажмете CTRL+6, чтобы вызвать графический интерфейс BinDiff, как показано здесь.
Следующим шагом является нажатие кнопки Diff Database и выбор другого файла IDB для сравнения. В зависимости от размера файлов это может занять минуту или две. После завершения сравнения в IDA появятся новые вкладки, включая "Matched Functions", "Primary Unmatched" и "Secondary Unmatched". Вкладка "Matched Functions" содержит функции, существующие в обоих файлах, которые могут включать или не включать изменения. Другую вкладку можно закрыть. Каждая функция получает оценку от 0 до 1,0 в столбце Similarity, как показано ниже. Чем ниже значение, тем больше изменилась функция между двумя файлами. Как заявляет Zynamics/Google в отношении вкладок Primary Unmatched и Secondary Unmatched, "Первая отображает функции, которые содержатся в текущей открытой базе данных и не связаны ни с одной функцией из различаемой базы данных, тогда как Secondary Unmatched subview содержит функции которые находятся в базе данных diff, но не связаны ни с какими функциями в первой".
Для получения наиболее точных результатов важно различать правильные версии файла. При переходе на сайт Microsoft TechNet для приобретения исправлений, опубликованных до апреля 2017 г., вы увидите столбец справа под названием "Updates Replaced". Вскоре будет рассмотрен процесс получения исправлений, начавшийся в апреле 2017 года. Щелкнув ссылку в этом месте и это приведет вас к предыдущему самому последнему обновлению исправляемого файла. Такой файл, как mshtml.dll, обновляется почти каждый месяц. Если вы сравниваете версию файла, полученную несколькими месяцами ранее, с только что выпущенным патчем, количество различий между двумя файлами очень затруднит анализ. Другие файлы не исправляются очень часто, поэтому, щелкнув вышеупомянутую ссылку, вы перейдете к последнему обновлению файла, о котором идет речь, чтобы вы могли различать подходящие версии. После того, как интересующая функция идентифицирована с помощью BinDiff, визуальное сравнение может быть сгенерировано либо щелчком правой кнопкой мыши по желаемой функции на вкладке "Matched Functions" и выбором "View Flowgraphs", либо щелчком по желаемой функции и нажатием CTRL+E. Ниже приведен пример визуального сравнения. Обратите внимание, что вы не сможете прочитать дисассемблерный код, потому что он уменьшен, чтобы поместиться на странице.
Turbodiff
Другой инструмент, который мы рассмотрим в этой главе, - turbodiff. Этот инструмент был выбран из-за его способности работать с бесплатной версией IDA 5.0. DarunGrim и patchdiff2 также являются отличными инструментами; однако для их использования требуется лицензионная копия IDA, что делает невозможным выполнение упражнений в этой главе без приобретения лицензионной копии для тех, кто читает ее. DarunGrim и patchdiff2 удобны для пользователя и просты в установке с помощью IDA. Diaphora - еще одна фантастическая альтернатива BinDiff, и вам предлагается попробовать ее и сравнить это в BinDiff.
Как упоминалось ранее, плагин turbodiff можно получить с веб-сайта http://corelabs.coresecurity.com/, и его можно бесплатно загрузить и использовать по лицензии GPLv2. Последний стабильный выпуск - версия 1.01b_r2, выпущенный 19 декабря 2011 года. Чтобы использовать turbodiff, вы должны загрузить два файла для сравнения по одному в IDA. После того, как IDA завершит свой автоматический анализ первого файла, вы нажмете CTRL+F11, чтобы открыть всплывающее меню turbodiff. Из вариантов при первом анализе файла выберите "take info from this idb" и нажмите "ОК". Повторите те же шаги для другого файла, который нужно включить в diff. Как только это будет выполнено с обоими файлами, которые нужно сравнить, снова нажмите CTRL+F11, выберите вариант "compare with…", а затем выберите другой файл IDB. Должно появиться следующее окно.
В столбце категории вы можете увидеть такие ярлыки, как идентичный, подозрительный+, подозрительный++ и измененный. Каждая метка имеет значение и может помочь исследователю выделить наиболее интересные функции, в первую очередь метки подозрительный+ и подозрительный++. Эти метки указывают на то, что были обнаружены контрольные суммы в одном или нескольких блоках выбранной функции, а также на то, изменилось ли количество инструкций. Когда вы дважды щелкаете имя нужной функции, отображается визуальное сравнение, при этом каждая функция отображается в своем собственном окне, как показано здесь.
Лабораторная работа 17-1. Наше первое сравнение.
В этой лабораторной работе вы выполните простое сравнение с кодом, ранее показанным в разделе "Application Diffing". Необходимо сравнить двоичные файлы ELF name и name2. Имя файла - это файл без исправлений, а name2 - с исправлением. Сначала необходимо запустить IDA 5.0, которое вы установили ранее. Как только она будет запущена, перейдите в File | New, выберите вкладку Unix во всплывающем окне и щелкните параметр ELF слева, как показано здесь, а затем щелкните OK.
Перейдите в папку C:\grayhat\app_diff\ и выберите файл name. Примите появившиеся параметры по умолчанию. IDA должна быстро завершить свой автоматический анализ, используя по умолчанию функцию main() в окне дизассемблирования, как показано ниже.
Нажмите CTRL+F11, чтобы открыть всплывающее окно turbodiff. Если он не появляется, вернитесь назад и убедитесь, что вы правильно скопировали необходимые файлы для turbodiff. С окном turbodiff на экране выберите опцию "take info from this idb" и нажмите OK, а затем еще раз "OK". Затем перейдите в File | New, и вы получите всплывающее окно с вопросом, хотите ли вы сохранить базу данных. Примите значения по умолчанию и нажмите "ОК". Повторите шаги выбора вкладки Unix | ELF Executable, а затем нажмите OK. Откройте двоичный файл ELF name2 и примите значения по умолчанию. Повторите шаги по открытию всплывающего окна turbodiff.
Теперь, когда вы выполнили это для обоих файлов, снова нажмите CTRL+F11, при этом файл name2 все еще открыт в IDA. Выберите вариант "compare with…" и нажмите "ОК". Выберите файл name.idb и нажмите "ОК", а затем — "ОК". Должно появиться следующее поле (возможно, вам придется отсортировать по категориям, чтобы воспроизвести точное изображение).
Обратите внимание, что функция getName() помечена как "подозрительная++". Дважды щелкните функцию getName(), чтобы открыть следующее окно.
На этом изображении в левом окне показана пропатченная функция, а в правом окне - непропатченная функция. Блок без исправлений использует функцию gets(), которая не обеспечивает проверку границ. Исправленный блок использует функцию fgets(), для которой требуется аргумент размера, чтобы предотвратить переполнение буфера. Пропатченный дизассемблерный код показан здесь:
Внутри этих двух функций была пара дополнительных блоков кода, но они белые и не содержат измененного кода. Это просто код защиты стека, который проверяет canaries стека, за которым следует эпилог функции. На этом лабораторная работа завершена. В дальнейшем мы посмотрим на real-world различия.
Процесс управления патчами
У каждого поставщика есть собственный процесс распространения исправлений, включая Oracle, Microsoft и Apple. У некоторых поставщиков есть установленное расписание выпуска исправлений, тогда как у других нет установленного расписания. Наличие постоянного цикла выпуска исправлений, например, используемого Microsoft, позволяет ответственным за управление большим количеством систем соответствующим образом планировать обновление. Внеполосные исправления могут быть проблематичными для организаций, потому что могут не быть доступных ресурсов для развертывания обновлений. Мы сосредоточимся в первую очередь на процессе управления исправлениями Microsoft, потому что это зрелый процесс, который часто используется для обнаружения уязвимостей с целью извлечения прибыли.
Microsoft Patch Tuesday
Второй вторник каждого месяца - это ежемесячный цикл исправлений Microsoft, иногда с выходом дополнительных исправлений из-за критического обновления. Процесс менялся с момента появления накопительных обновлений Windows 10, вступающих в силу в Windows 7 и 8 с октября 2016 года, а также изменения способа загрузки исправлений. Вплоть до апреля 2017 г. сводку и исправления безопасности для каждого обновления можно было найти по адресу https://technet.microsoft.com/en-us/security/bulletin. Начиная с апреля 2017 г., исправления можно получить на сайте Microsoft Security TechCenter по адресу https://portal.msrc.microsoft.com/en-us/security-guidance, а сводную информацию можно найти на сайте https://portal.msrc.microsoft.com/en-us/security-guidance/summary. Исправления обычно получаются с помощью инструмента Windows Update на панели управления Windows или управляются централизованно с помощью такого продукта, как Windows Server Update Services (WSUS) или Windows Update для бизнеса (WUB). Если исправления необходимы для распространения, их можно получить по вышеупомянутой ссылке TechNet.
Каждый бюллетень исправлений связан с дополнительной информацией об обновлении. Некоторые обновления являются результатом публично обнаруженной уязвимости, в то время как большинство из них связано с той или иной формой скоординированного частного раскрытия информации. На следующем изображении показан пример одной такой уязвимости, раскрытой в частном порядке.
Как видите, об уязвимости предоставляется лишь ограниченная информация. Чем больше информации предоставлено, тем больше вероятность, что кто-то сможет быстро найти исправленный код и создать работающий эксплоит. В зависимости от размера обновления и сложности уязвимости обнаружение только исправленного кода может оказаться сложной задачей. Часто уязвимое состояние носит чисто теоретический характер или может возникать только при очень специфических условиях. Это может увеличить сложность определения основной причины и создания POC, который успешно запускает ошибку. Как только основная причина определена и уязвимый код найден и доступен для анализа в отладчике, необходимо определить, насколько сложно будет добиться выполнения кода, если это применимо.
Получение и извлечение исправлений Microsoft
Скоро мы дойдем до лабораторной, но сначала давайте рассмотрим пример получения и извлечения накопительного обновления для Windows 10. Накопительные обновления до апреля 2017 г. доступны в Microsoft TechNet по адресу https://technet.microsoft.com/en-us/library/security/dn631937.aspx. Накопительные обновления с апреля 2017 г. доступны по адресу https://portal.msrc.microsoft.com/en-us/security-guidance. В нашем примере мы смотрим на MS17-010, в котором исправлено несколько ошибок с SMB и который был выпущен в марте 2017 года. Информация об этом раскрытии доступна по адресу https://technet.microsoft.com/en-us/library/security/ms17-010.aspx. Заголовки исправлений безопасности показаны на следующем изображении.
Мы сосредоточимся на CVE-2017-0147, "Уязвимость Windows SMB, связанная с раскрытием информации", чтобы просто определить исправление, но сначала мы должны загрузить и извлечь обновление. Используя вышеупомянутую ссылку на MS17-010, щелкните и загрузите 32-разрядное обновление Windows 10 через сервер каталогов Microsoft, как показано ниже.
Обведенная область слева - это ссылка для загрузки обновления через сервер каталога. Обведенная ссылка справа - это поле Updates Replaced. Щелкнув по этой ссылке, вы перейдете к информации об обновлении, когда в последний раз были исправлены соответствующий файл или файлы. Если файл srv.sys был исправлен в октябре 2017 года, а последний раз он был исправлен до этого в июле 2017 года, ссылка Updates Replaced приведет вас к этому обновлению. Это важно отметить, потому что вы всегда хотите различать версии, наиболее близкие друг к другу, чтобы любые изменения функций были связаны с интересующими вас CVE.
Теперь, когда было загружено накопительное обновление для 32-разрядной версии Windows 10 за март 2017 г., мы будем использовать инструмент PatchExtract, созданный Greg Linares, чтобы упростить извлечение. PatchExtract - это сценарий PowerShell, который использует Microsoft инструмент expand и другие команды для извлечения и упорядочивания множества файлов, содержащихся в загруженном файле MSU и последующих файлах CAB. На момент написания этой статьи PatchExtract версии 1.3 все еще оставался самой последней. Он доступен по адресу https://pastebin.com/VjwNV23n. Greg пользуется псевдонимом Twitter @Laughing_Mantis. Также существует связанный сценарий PowerShell под названием PatchClean, который помогает в дальнейшей организации извлеченных обновлений и гарантирует, что только файлы, которые были изменены в течение последних 30 дней, помечены как интересные. Причина в том, что накопительные обновления содержат все обновления, относящиеся к этой версии Windows, за многие месяцы. PatchClean перемещает все файлы старше 30 дней в "старую" папку, чтобы можно было уделить внимание недавно обновленным файлам. Это по-прежнему требует, чтобы вы выполнили проверку, и вы также должны знать дату, когда выполняется извлечение. Если вы выполняете извлечение и запускаете PatchClean после даты выпуска первоначального исправления, вам может потребоваться соответствующая настройка даты и времени.
Следующая команда является примером запуска PatchExtract из командной строки администратора для извлечения файлов и исправлений из накопительного обновления за март 2017 года:
Команда может выглядеть длинной, но в основном это связано с введенным путем и длинным именем кумулятивного обновления. После ввода PatchExtract выполнит извлечение, что может занять несколько минут в зависимости от размера файла. Накопительные обновления Windows 10 x64 могут иметь размер более 1 ГБ, поэтому мы выбрали версию x86. Как только оно будет закончено, у нас останется несколько папок. В нашем примере мы хотим зайти в папку "x86" и посмотреть что внутри. Там есть 1165 вложенных папок. Найдите минутку, чтобы подумать о нашей цели. Мы хотим идентифицировать только файлы, относящиеся к мартовскому циклу исправлений 2017 года, но у нас осталось 1165 подпапок. Здесь в игру вступает инструмент PatchClean. Сначала мы хотим зайти и изменить дату системы, используемой для анализа, на дату вторника исправлений для марта 2017 года. Это будет вторник, 14 марта. По умолчанию PatchClean возвращается на 30 дней назад с даты и перемещает все файлы, время изменения которых превышает указанное, в "старую" папку. Это позволяет нам видеть, какие файлы были изменены за последние 30 дней.
После завершения скрипта у нас остается 318 из 1165 исходных папок. Это большое количество неудивительно, поскольку Microsoft пропустила вторник исправлений в феврале 2017 года из-за задержек с исправлением уязвимостей SMB.
Лабораторная 17-2: Diffing MS17-010
В этой лабораторной работе вы будете использовать два файла srv.sys, доступные в репозитории Gray Hat. Один находится в папке "Old", а другой - в папке "New". Новый из обновления за март 2017 года. Примеры, показанные в этой лабораторной работе, взяты из IDA 7.0 в режиме совместимости с x86 для использования подключаемого модуля BinDiff 4.3.
Первый шаг - открыть вашу лицензионную копию IDA или бесплатную версию 5.0, если у вас нет лицензионной версии, и открыть новый файл srv.sys. Разрешите IDA завершить анализ. По завершении сохраните базу данных и откройте старую версию srv.sys. После завершения анализа вы готовы к выполнению сравнения. Загрузив cтарый файл srv.sys, нажмите CTRL+6, чтобы открыть меню BinDiff, а затем щелкните Diff Database .… Если вы используете turbodiff, нажмите CTRL+F11, чтобы вызвать его меню, и используйте тот же метод, что и в лабораторной работе 17-1.
После нажатия кнопки Diff Database… перейдите к IDB-файлу «New» srv.sys и выполните сравнение. Через несколько секунд сравнение должно быть завершено, и у вас должны появиться новые вкладки внутри IDA. То, что нас интересует, - это "Matched Functions". В результатах сравнения, показанных ниже, мы выбрали функцию SrvSmbTransaction(). Часто, когда есть более чем несколько функций с изменениями, вы должны смотреть на имена функций при определении потенциальных интересующих функций.
Нажмите CTRL+E, чтобы выполнить графическое сравнение. При использовании turbodiff обязательно используйте метод, описанный ранее, для графического сравнения. Вот "уменьшенный" обзор графического сравнения.
Если вы щелкнете по любому из ассемблерных блоков, а не просто увеличите масштаб, экран изменит конфигурацию и отобразит только группу вокруг выбранного блока. Если вы хотите вернуться к основному обзору, вы должны щелкнуть значок "Select Ancestors" на главной панели ленты BinDiff, как показано ниже.
В этом примере непропатченная версия srv.sys находится слева, а пропатченная версия - справа. После увеличения и осмотра различий мы обнаруживаем интересное изменение. Следующее изображение взято из непропатченной версии, и вы можете видеть, что функция ExecuteTransaction вызывается, как указано.
Теперь посмотрим на пропатченную версию. Тот же самый блок кода, который приводит к вызову функции ExecuteTransaction, теперь вместо этого сначала выполняет некоторые вызовы функции memset.
Вы все еще можете видеть функцию ExecuteTransaction в среднем блоке, но поток должен сначала пройти через вызовы функции memset, прежде чем попасть в этот блок. Не стесняйтесь следовать за парой блоков на этом пути. Вызов функции memset, вероятно, устраняет утечку информации, связанную с CVE-2017-0147.
Сравнение патча для эксплуатации
В предыдущем сравнении патчей Microsoft с MS17-010 мы выявили изменения кода, которые разрешили проблему раскрытия информации; однако это не привело нас к эксплуатации ошибки. В следующем примере мы рассмотрим ошибку загрузки DLL, которая может позволить разрешить удаленное выполнение кода и запустить работающий эксплойт. И MS16-009, и MS16-014 заявляют о решении CVE-2016-0041, которая связана с "DLL Loading Remote Code Execution Vulnerability". Автор обнаружил, что интересующий нас файл был доступен в MS16-009 патче.
Чтобы оставаться последовательным, ошибка была обнаружена Greg Linares, который написал ранее описанный инструмент PatchExtract.
DLL Side-Loading Bugs
При проверке в Интернете вы можете получить различные определения того, что представляет собой DLL side-loading bug. В зависимости от настроек в реестре, а также аргументов, переданных функции загрузки DLL, такой как набор функций LoadLibrary(), может быть один или несколько способов принудительной загрузки нежелательной DLL. Давайте воспользуемся простой аналогией, чтобы описать пример проблемы. Мы предполагаем, что вы всегда кладете соль и перец, используемые в еде, в определенное место на кухне. Представьте, что в следующий раз, когда вы воспользуетесь ими, их нет в этом месте. Вы можете отказаться от соли и перца или искать их в других местах, например, в других шкафах, столах и прилавках.
В конце концов, вы либо найдете соль и перец, либо откажетесь. Это не так уж отличается от порядка поиска, используемого при загрузке DLL. Более безопасный параметр - разрешить загрузку желаемой DLL только из очень определенного места, например C:\Windows\System32\.
Менее безопасный вариант - разрешить загрузку DLL из разных мест на основе приоритета порядка поиска.
Давайте подробнее рассмотрим, как и откуда можно загружать библиотеки DLL. Во-первых, в последних нескольких версиях Windows есть контейнер реестра, обычно в HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SessionManager\KnownDLLs\.
Здесь показан пример.
В этом контейнере хранятся библиотеки DLL, которые обычно используются для ускорения загрузки программ, но некоторые также рассматривают его как средство контроля безопасности, поскольку он указывает, что перечисленные библиотеки DLL могут быть загружены только из папки System32 в C:\Windows\System32\ или C:\Windows\SysWOW64\. Затем функцию LoadLibraryEx можно использовать для динамической загрузки библиотек DLL, запрошенных процессом:
Одним из обязательных аргументов является dwFlags, который используется для указания того, откуда потенциально может быть загружена DLL, и других вариантов поведения, например, связанных с AppLocker, и того, что произойдет при входе в отношении выполнения кода.
Дополнительную информацию можно найти на https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx. Если для аргумента dwFlags оставить значение по умолчанию 0, поведение будет таким же, как у более старой функции LoadLibrary, которая реализует SafeDllSearchMode. Как заявляет Microsoft:
"Если включен SafeDllSearchMode, порядок поиска будет следующим:
- Каталог, из которого загружено приложение.
- Системный каталог. Используйте функцию GetSystemDirectory, чтобы получить путь к этому каталогу.
- 16-битный системный каталог. Нет функции, которая получает путь к этому каталогу, но он ищется.
- Каталог Windows. Используйте функцию GetWindowsDirectory, чтобы получить путь к этому каталогу.
- Текущий каталог.
- Каталоги, перечисленные в переменной среды PATH.
Обратите внимание, что это не включает путь для каждого приложения, указанный в разделе реестра App Paths. Ключ App Paths не используется при вычислении пути поиска DLL ".
Из этих вариантов 5 и 6 потенциально представляют угрозу безопасности, поскольку они могут включать в себя местоположения, на которые может повлиять злоумышленник, например местоположения, доступные для записи всем. Обычная опция dwFlags, используемая для защиты вызовов LoadLibraryEX, - это 0x800 LOAD_LIBRARY_SEARCH_SYSTEM32. Этот параметр ограничивает загрузку библиотеки DLL только папкой System32.
Лабораторная 17-3: Diffing MS16-009
В этой лабораторной работе мы анализируем исправление безопасности, связанное с MS16-009 и MS16-014, которые оба утверждают, что устраняют CVE-2016-0041. Процесс извлечения патча завершен за вас и доступен в репозитории кода Gray Hat. В показанных примерах различий патчей используются IDA 7.0 x64 и BinDiff 4.3. Операционные системы, задействованные в эксплуатации, - это Kali Linux x64 и Windows 10 x64 Home Edition, номер сборки 10586. Версия Skype, используемая в базовой сборке Windows 10 — 7.18.0.112.
При извлечении патча MS16-009 мы определили, что файл urlmon.dll был обновлен. Как обновленная версия urlmon.dll, так и предыдущая были предоставлены вам в рамках этой лабораторной работы. Первый шаг - дизассемблировать их с помощью IDA и выполнить сравнение. Вы должны использовать BinDiff 4.3 с IDA, который поддерживает дизассемблирование 64-битных входных файлов, поскольку эта ошибка затрагивала только 64-битную Windows. Если у вас нет возможности дизассемблировать 64-разрядные входные файлы и сохранить файлы базы данных IDA .idb, вы не сможете выполнить эту лабораторную работу, а вместо этого сможете только прочитать следующие разделы. Вы также можете изучить radare2 как альтернативу IDA.
Теперь выполните сравнение, используя одну из этих опций. На следующем изображении показаны результаты при использовании BinDiff.
Согласно BinDiff изменилась только одна функция. Нет ничего проще, чем дать нам возможность сосредоточиться на функции, связанной с исправлением ошибки. Имя функции — BuildUserAgentStringMobileHelper(). Давайте нажмем CTRL+E, чтобы выполнить графическое сравнение. На следующем изображении показаны общие результаты.
При увеличении масштаба изменений кода мы можем быстро идентифицировать следующий блок.
Вы должны сразу заметить, что в непропатченной версии слева аргумент dwFlags подвергается операции XOR с 0. Это заставит SafeDllSearchMode вступить в силу. В исправленной версии справа для dwFlags установлено значение 0x800, что ограничит загрузку желаемой DLL в папку System32. Мы хотим увидеть, какая DLL загружается в это место в коде. Для этого мы можем просто вернуться в IDA и перейти к функции BuildUserAgentStringMobileHelper(). Самый простой способ быстро туда добраться - просто щелкнуть окно функций в IDA и начать вводить желаемое имя функции. Затем дважды щелкните по нему, чтобы вызвать дизассемблирование. Вы также можете пропустите этот шаг, щелкнув в главном окне дизассемблирования IDA, нажав G и введя адрес, куда вы хотите перейти. Оглядываясь назад на непропатченные результаты в BinDiff, мы видим, что интересующий адрес — 0x18003BCB1. После перехода по этому адресу мы получаем желаемый результат, как показано ниже.
Как видите, в этот момент кода загружается DLL-библиотека phoneinfo.dll. Вы можете пропустить следующий шаг, но цель состоит в том, чтобы показать вам, как определить, какие приложения нуждаются в этой DLL. Во-первых, в корне файловой системы был выполнен исчерпывающий поиск, чтобы увидеть, существует ли файл phoneinfo.dll в базовой установке Windows 10 x64. Было подтверждено, что файл не существует. Затем мы хотим запустить инструмент Process Monitor от Microsoft (доступный по адресу https://docs.microsoft.com/en-us/sysinternals/downloads/procmon). На следующем изображении показаны два фильтра, примененные к инструменту Process Monitor после его запуска.
Первый фильтр вступает в силу, если "Результат" - "NAME NOT FOUND". Второй фильтр предназначен для «Пути» и заканчивается на "phoneinfo.dll". После применения этих фильтров мы запускаем различные приложения, такие как IE11, Edge, Skype, OneDrive, Word и другие.
Поскольку DLL называется phoneinfo.dll, имеет смысл попробовать определенные приложения на основе только имени. Ниже приводится пример результатов.
Вы можете видеть, что и Internet Explorer, и Skype пытаются загрузить DLL. Справа вы можете увидеть все отмеченные места. Это поведение SafeDllSearchMode. Примечательно, что мы видим, что C:\Python27\ является одним из местоположений проверки. Если мы сможем создать вредоносную DLL с помощью msfvenom, используя Meterpreter в качестве полезной нагрузки, мы сможем получить удаленный сеанс с уязвимой системой Windows 10. На следующем изображении показано создание вредоносного файла phoneinfo.dll, который содержит полезную нагрузку Meterpreter, которая подключается к нашей системе Kali Linux. Сразу после этого мы используем модуль Python SimpleHTTPServer для передачи вредоносной DLL системе-жертве. Мы не применяли никаких методов кодирования обхода антивируса (AV), или других методов, поэтому мы отключили Защитник Windows, чтобы протестировать эксплойт.
Затем мы запускаем прослушиватель Metasploit для получения входящего соединения в случае успеха нашей атаки.
Когда слушатели Python и Metasploit работают, мы возвращаемся в систему Windows и используем Internet Explorer для подключения к системе Kali через порт 8080. Затем мы загружаем файл phoneinfo.dll и сохраняем его в C:\Python27\, как показано здесь.
Затем мы запускаем Skype, который должен загрузить вредоносную DLL из папки C:\Python27\ как часть операции SafeDllSearchMode, как показано ниже.
Когда приложение Skype запущено, мы снова переключаемся на Kali Linux, чтобы увидеть, установлен ли сеанс Meterpreter.
Успех! Если мы хотим проделать это в условиях дикой среды, нужно учесть несколько вещей. Во-первых, мы, безусловно, хотели бы закодировать полезную нагрузку таким образом, чтобы избежать обнаружения AV. Во-вторых, мы хотели бы найти способ обманом заставить жертву загрузить вредоносную DLL в свою систему в определенное место. Это можно сделать с помощью фишинга. Заставить жертву думать, что существует критическое обновление Skype и что DLL необходимо разместить в определенном месте.
Резюме
В этой главе были представлены двоичное сравнение и различные инструменты, которые помогут ускорить анализ. Мы рассмотрели простой пример, подтверждающий концепцию приложения, а затем изучили реальные исправления, чтобы определить уязвимости и проверить наши предположения. Это приобретенный навык, тесно связанный с вашим опытом отладки и чтения дизассемблированного кода. Чем чаще вы это делаете, тем лучше вы будете определять изменения кода и потенциальные исправленные уязвимости. Microsoft прекратила поддержку Windows XP и Vista; однако некоторые версии, например с XP Embedded, все еще поддерживаются и получают исправления. Это может дать возможность продолжить анализ исправлений в операционной системе, которая не имеет такой сложности. Microsoft также нередко незаметно вносит изменения в код с помощью другого патча. Иногда это отличается в разных версиях Windows, где одна версия Windows может предоставить больше информации, чем различие другой версии.
Источник: Gray Hat Hacking the Ethica Hacker's Handbook 5th
Автор перевода: yashechka
Переведено специально для портала xss.pro (c)
Последнее редактирование модератором: