• XSS.stack #1 – первый литературный журнал от юзеров форума

Мануал/Книга 1-Day эксплойты - анализ патчей безопасности Microsoft v2.0

yashechka

Генератор контента.Фанат Ильфака и Рикардо Нарвахи
Эксперт
Регистрация
24.11.2012
Сообщения
2 344
Реакции
3 563
В ответ на прибыльный рост исследований уязвимостей, уровень интереса к двоичному сравнению пропатченных уязвимостей продолжает расти. Обнаруженные в частном порядке и обнаруженные внутри компании уязвимости обычно предоставляют ограниченные технические сведения. Процесс бинарного сравнения можно сравнить с охотой за сокровищами, когда исследователям предоставляется ограниченная информация о местонахождении и деталях уязвимости или "cхороненного сокровища". При наличии необходимых навыков и инструментов исследователь может найти и идентифицировать изменения кода, а затем разработать работающий эксплоит.

В этой главе мы рассмотрим следующие темы:

- Сравнения приложений и патчей
- Инструменты для двоичного сравнения
- Процесс управления патчами
- Real-world сравнения

Введение в двоичное сравнение

При внесении изменений в скомпилированный код, такой как библиотеки, приложения и драйверы, разница между пропатченными и непропатченными версиями может дать возможность обнаружить уязвимости. На самом базовом уровне двоичное сравнение - это процесс выявления различий между двумя версиями одного и того же файла, такими как версия 1.2 и 1.3. Возможно, наиболее распространенной целью двоичных сравнений являются исправления Microsoft; однако это можно применить ко многим различным типам скомпилированного кода. Доступны различные инструменты для упрощения процесса сравнения двоичных файлов, что позволяет быстро определять изменения кода в дизассемблере.

Сравнение приложений

Обычно выпускаются новые версии приложений. Причина выпуска может включать в себя введение новых функций, изменения кода для поддержки новых платформ или версий ядра, использование новых средств контроля безопасности во время компиляции, таких как canaries или Control Flow Guard (CFG), а также исправление уязвимостей. Часто новая версия может включать комбинацию вышеупомянутых рассуждений. Чем больше изменений в коде приложения, тем сложнее выявить пропатченные уязвимости. Большая часть успеха в выявлении изменений кода, связанных с исправлениями уязвимостей, зависит от ограниченного раскрытия информации. Многие организации предпочитают публиковать минимальную информацию о характере исправления безопасности. Чем больше улик мы сможем получить из этой информации, тем больше вероятность, что мы обнаружим уязвимость. Эти типы подсказок будут показаны в реальных сценариях позже в этой главе.

Здесь показан простой пример фрагмента кода C, который включает уязвимость:

1.png


А здесь пропатченный код

2.png

Проблема с первым фрагментом заключается в использовании функции 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, как показано здесь.

3.png


Следующим шагом является нажатие кнопки 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, но не связаны ни с какими функциями в первой".


4.png


Для получения наиболее точных результатов важно различать правильные версии файла. При переходе на сайт Microsoft TechNet для приобретения исправлений, опубликованных до апреля 2017 г., вы увидите столбец справа под названием "Updates Replaced". Вскоре будет рассмотрен процесс получения исправлений, начавшийся в апреле 2017 года. Щелкнув ссылку в этом месте и это приведет вас к предыдущему самому последнему обновлению исправляемого файла. Такой файл, как mshtml.dll, обновляется почти каждый месяц. Если вы сравниваете версию файла, полученную несколькими месяцами ранее, с только что выпущенным патчем, количество различий между двумя файлами очень затруднит анализ. Другие файлы не исправляются очень часто, поэтому, щелкнув вышеупомянутую ссылку, вы перейдете к последнему обновлению файла, о котором идет речь, чтобы вы могли различать подходящие версии. После того, как интересующая функция идентифицирована с помощью BinDiff, визуальное сравнение может быть сгенерировано либо щелчком правой кнопкой мыши по желаемой функции на вкладке "Matched Functions" и выбором "View Flowgraphs", либо щелчком по желаемой функции и нажатием CTRL+E. Ниже приведен пример визуального сравнения. Обратите внимание, что вы не сможете прочитать дисассемблерный код, потому что он уменьшен, чтобы поместиться на странице.

5.png



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. Должно появиться следующее окно.

6.png



В столбце категории вы можете увидеть такие ярлыки, как идентичный, подозрительный+, подозрительный++ и измененный. Каждая метка имеет значение и может помочь исследователю выделить наиболее интересные функции, в первую очередь метки подозрительный+ и подозрительный++. Эти метки указывают на то, что были обнаружены контрольные суммы в одном или нескольких блоках выбранной функции, а также на то, изменилось ли количество инструкций. Когда вы дважды щелкаете имя нужной функции, отображается визуальное сравнение, при этом каждая функция отображается в своем собственном окне, как показано здесь.


7.png



Лабораторная работа 17-1. Наше первое сравнение.

В этой лабораторной работе вы выполните простое сравнение с кодом, ранее показанным в разделе "Application Diffing". Необходимо сравнить двоичные файлы ELF name и name2. Имя файла - это файл без исправлений, а name2 - с исправлением. Сначала необходимо запустить IDA 5.0, которое вы установили ранее. Как только она будет запущена, перейдите в File | New, выберите вкладку Unix во всплывающем окне и щелкните параметр ELF слева, как показано здесь, а затем щелкните OK.


8.png


Перейдите в папку C:\grayhat\app_diff\ и выберите файл name. Примите появившиеся параметры по умолчанию. IDA должна быстро завершить свой автоматический анализ, используя по умолчанию функцию main() в окне дизассемблирования, как показано ниже.



9.png



Нажмите 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 и нажмите "ОК", а затем — "ОК". Должно появиться следующее поле (возможно, вам придется отсортировать по категориям, чтобы воспроизвести точное изображение).

10.png



Обратите внимание, что функция getName() помечена как "подозрительная++". Дважды щелкните функцию getName(), чтобы открыть следующее окно.

11.png


На этом изображении в левом окне показана пропатченная функция, а в правом окне - непропатченная функция. Блок без исправлений использует функцию gets(), которая не обеспечивает проверку границ. Исправленный блок использует функцию fgets(), для которой требуется аргумент размера, чтобы предотвратить переполнение буфера. Пропатченный дизассемблерный код показан здесь:


12.png


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

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

13.png


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

14.png



Мы сосредоточимся на CVE-2017-0147, "Уязвимость Windows SMB, связанная с раскрытием информации", чтобы просто определить исправление, но сначала мы должны загрузить и извлечь обновление. Используя вышеупомянутую ссылку на MS17-010, щелкните и загрузите 32-разрядное обновление Windows 10 через сервер каталогов Microsoft, как показано ниже.

15.png



Обведенная область слева - это ссылка для загрузки обновления через сервер каталога. Обведенная ссылка справа - это поле 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 года:

16.png

Команда может выглядеть длинной, но в основном это связано с введенным путем и длинным именем кумулятивного обновления. После ввода PatchExtract выполнит извлечение, что может занять несколько минут в зависимости от размера файла. Накопительные обновления Windows 10 x64 могут иметь размер более 1 ГБ, поэтому мы выбрали версию x86. Как только оно будет закончено, у нас останется несколько папок. В нашем примере мы хотим зайти в папку "x86" и посмотреть что внутри. Там есть 1165 вложенных папок. Найдите минутку, чтобы подумать о нашей цели. Мы хотим идентифицировать только файлы, относящиеся к мартовскому циклу исправлений 2017 года, но у нас осталось 1165 подпапок. Здесь в игру вступает инструмент PatchClean. Сначала мы хотим зайти и изменить дату системы, используемой для анализа, на дату вторника исправлений для марта 2017 года. Это будет вторник, 14 марта. По умолчанию PatchClean возвращается на 30 дней назад с даты и перемещает все файлы, время изменения которых превышает указанное, в "старую" папку. Это позволяет нам видеть, какие файлы были изменены за последние 30 дней.

17.png



После завершения скрипта у нас остается 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.

18.png


После нажатия кнопки Diff Database… перейдите к IDB-файлу «New» srv.sys и выполните сравнение. Через несколько секунд сравнение должно быть завершено, и у вас должны появиться новые вкладки внутри IDA. То, что нас интересует, - это "Matched Functions". В результатах сравнения, показанных ниже, мы выбрали функцию SrvSmbTransaction(). Часто, когда есть более чем несколько функций с изменениями, вы должны смотреть на имена функций при определении потенциальных интересующих функций.

19.png


Нажмите CTRL+E, чтобы выполнить графическое сравнение. При использовании turbodiff обязательно используйте метод, описанный ранее, для графического сравнения. Вот "уменьшенный" обзор графического сравнения.

20.png


Если вы щелкнете по любому из ассемблерных блоков, а не просто увеличите масштаб, экран изменит конфигурацию и отобразит только группу вокруг выбранного блока. Если вы хотите вернуться к основному обзору, вы должны щелкнуть значок "Select Ancestors" на главной панели ленты BinDiff, как показано ниже.

21.png

В этом примере непропатченная версия srv.sys находится слева, а пропатченная версия - справа. После увеличения и осмотра различий мы обнаруживаем интересное изменение. Следующее изображение взято из непропатченной версии, и вы можете видеть, что функция ExecuteTransaction вызывается, как указано.

22.png



Теперь посмотрим на пропатченную версию. Тот же самый блок кода, который приводит к вызову функции ExecuteTransaction, теперь вместо этого сначала выполняет некоторые вызовы функции memset.

23.png



Вы все еще можете видеть функцию 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\.
Здесь показан пример.

24.png


В этом контейнере хранятся библиотеки DLL, которые обычно используются для ускорения загрузки программ, но некоторые также рассматривают его как средство контроля безопасности, поскольку он указывает, что перечисленные библиотеки DLL могут быть загружены только из папки System32 в C:\Windows\System32\ или C:\Windows\SysWOW64\. Затем функцию LoadLibraryEx можно использовать для динамической загрузки библиотек DLL, запрошенных процессом:

25.png



Одним из обязательных аргументов является 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.

26.png



Согласно BinDiff изменилась только одна функция. Нет ничего проще, чем дать нам возможность сосредоточиться на функции, связанной с исправлением ошибки. Имя функции — BuildUserAgentStringMobileHelper(). Давайте нажмем CTRL+E, чтобы выполнить графическое сравнение. На следующем изображении показаны общие результаты.

27.png



При увеличении масштаба изменений кода мы можем быстро идентифицировать следующий блок.

28.png


Вы должны сразу заметить, что в непропатченной версии слева аргумент dwFlags подвергается операции XOR с 0. Это заставит SafeDllSearchMode вступить в силу. В исправленной версии справа для dwFlags установлено значение 0x800, что ограничит загрузку желаемой DLL в папку System32. Мы хотим увидеть, какая DLL загружается в это место в коде. Для этого мы можем просто вернуться в IDA и перейти к функции BuildUserAgentStringMobileHelper(). Самый простой способ быстро туда добраться - просто щелкнуть окно функций в IDA и начать вводить желаемое имя функции. Затем дважды щелкните по нему, чтобы вызвать дизассемблирование. Вы также можете пропустите этот шаг, щелкнув в главном окне дизассемблирования IDA, нажав G и введя адрес, куда вы хотите перейти. Оглядываясь назад на непропатченные результаты в BinDiff, мы видим, что интересующий адрес — 0x18003BCB1. После перехода по этому адресу мы получаем желаемый результат, как показано ниже.

29.png


Как видите, в этот момент кода загружается DLL-библиотека phoneinfo.dll. Вы можете пропустить следующий шаг, но цель состоит в том, чтобы показать вам, как определить, какие приложения нуждаются в этой DLL. Во-первых, в корне файловой системы был выполнен исчерпывающий поиск, чтобы увидеть, существует ли файл phoneinfo.dll в базовой установке Windows 10 x64. Было подтверждено, что файл не существует. Затем мы хотим запустить инструмент Process Monitor от Microsoft (доступный по адресу https://docs.microsoft.com/en-us/sysinternals/downloads/procmon). На следующем изображении показаны два фильтра, примененные к инструменту Process Monitor после его запуска.

30.png


Первый фильтр вступает в силу, если "Результат" - "NAME NOT FOUND". Второй фильтр предназначен для «Пути» и заканчивается на "phoneinfo.dll". После применения этих фильтров мы запускаем различные приложения, такие как IE11, Edge, Skype, OneDrive, Word и другие.
Поскольку DLL называется phoneinfo.dll, имеет смысл попробовать определенные приложения на основе только имени. Ниже приводится пример результатов.

31.png


Вы можете видеть, что и Internet Explorer, и Skype пытаются загрузить DLL. Справа вы можете увидеть все отмеченные места. Это поведение SafeDllSearchMode. Примечательно, что мы видим, что C:\Python27\ является одним из местоположений проверки. Если мы сможем создать вредоносную DLL с помощью msfvenom, используя Meterpreter в качестве полезной нагрузки, мы сможем получить удаленный сеанс с уязвимой системой Windows 10. На следующем изображении показано создание вредоносного файла phoneinfo.dll, который содержит полезную нагрузку Meterpreter, которая подключается к нашей системе Kali Linux. Сразу после этого мы используем модуль Python SimpleHTTPServer для передачи вредоносной DLL системе-жертве. Мы не применяли никаких методов кодирования обхода антивируса (AV), или других методов, поэтому мы отключили Защитник Windows, чтобы протестировать эксплойт.

32.png


Затем мы запускаем прослушиватель Metasploit для получения входящего соединения в случае успеха нашей атаки.

33.png



Когда слушатели Python и Metasploit работают, мы возвращаемся в систему Windows и используем Internet Explorer для подключения к системе Kali через порт 8080. Затем мы загружаем файл phoneinfo.dll и сохраняем его в C:\Python27\, как показано здесь.

34.png


Затем мы запускаем Skype, который должен загрузить вредоносную DLL из папки C:\Python27\ как часть операции SafeDllSearchMode, как показано ниже.


35.png


Когда приложение Skype запущено, мы снова переключаемся на Kali Linux, чтобы увидеть, установлен ли сеанс Meterpreter.

36.png

Успех! Если мы хотим проделать это в условиях дикой среды, нужно учесть несколько вещей. Во-первых, мы, безусловно, хотели бы закодировать полезную нагрузку таким образом, чтобы избежать обнаружения 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)
 
Последнее редактирование модератором:
Пожалуйста, обратите внимание, что пользователь заблокирован
Файлы для лабораторной работы скачать можно тут -> https://github.com/GrayHatHacking/GHHv5/tree/master/ch17

PATCHCLEAN.PS1
Код:
<#
================
PATCHCLEAN.PS1
=================
Version 1.0 Patch Folder Cleaner by Greg Linares (@Laughing_Mantis)

This Tool will go through the patch folders created by PatchExtract.PS1 and look for files created older
than 30 days prior to the current date and move these to a sub folder named "OLD" in the patch folders.

This will help identify higher priority binaries that were likely updated in the current patch cycle window.

======= 
USAGE
=======
Powershell -ExecutionPolicy Bypass -File PatchClean.ps1 -Path C:\Patches\MS16-121\x86\

This would go through the x86 folder and create a subfolder named C:\Patches\MS16-121\x86\OLD\ and place
older files and their folders in that directory.

Files remaining in C:\Patches\MS16-121\x86\ should be considered likely targets for containing patched binaries

Empty folders are automatically cleaned and removed at the end of processing.

-PATH <STRING:FolderPath> [REQUIRED] [NO DEFAULT]
    Specified the folder that the script will parse and look for older files


================
VERSION HISTORY
================

Oct 20, 2016 - Version 1 - Initial Release


==========
LICENSING
==========
This script is provided free as beer.  It probably has some bugs and coding issues, however if you like it or find it
useful please give me a shout out on twitter @Laughing_Mantis.  Feedback is encouraged and I will be likely releasing
new scripts and tools and training in the future if it is welcome.


-GLin

#>

Param
(

    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [ValidateNotNullOrEmpty()]
    [string]$PATH = ""
)


Clear-Host

if ($PATH -eq "")
{
    Throw ("Error: No PATH specified.  Specify a valid folder containing extracted patch files required. Generated by PatchExtract.ps1 ")

}

if (!(Test-Path $PATH))
{
    Throw ("Error: Invalid PATH specified '$PATH' does not exist.")
}

$OldDir = Join-Path -path $PATH -ChildPath "OLD"

if (!(Test-Path $OldDir -pathType Container))
{
    New-Item $OldDir -Force -ItemType Directory
    Write-Host "Making $OldDir Folder" -ForegroundColor Green
}

$FolderCount = 0
$FileCount = 0
$OldFiles = Get-ChildItem -Path $PATH -Recurse -File -Force -ErrorAction SilentlyContinue | Where{$_.LastWriteTime -lt (Get-Date).AddDays(-30)}


foreach ($OldFile in $OldFiles)
{
    try
    {
        $FileCount++
        $fileDir = (Get-Item($OldFile).DirectoryName)
        $folderName = (Get-Item $fileDir ).Basename
        $MoveDir = JOIN-Path -path $OldDir -ChildPath $folderName
        if (!(Test-Path $movedir))
        {
            Write-Host "Creating $folderName to $OldDir" -ForegroundColor Green
            New-Item $MoveDir -Force -ItemType Directory
            $FolderCount++
        }
        Move-Item $OldFile.fullname $MoveDir -Force

    }
    catch
    {
        Write-Host ("Error Processing " + $OldFile.fullname) -ForegroundColor Red
        Write-Host $_.Exception.Message
        Write-Host $_.Exception.ItemName
    }
}

#Clean Up Empty Folders

$EmptyFolders = Get-ChildItem -Path $PATH  -Recurse| Where-Object {$_.PSIsContainer -eq $True} | Where-Object {$_.GetFiles().Count -eq 0 -and $_.GetDirectories().Count -eq 0 } | Select-Object FullName


foreach ($EmptyFolder in $EmptyFolders)
{
    try
    {
        Write-Host ("Removing Empty Folder: " + $EmptyFolder.FullName) -ForegroundColor Yellow
        Remove-Item -Path $EmptyFolder.FullName -Force
    }
    catch
    {
        Write-Host ("Error Removing: " + $EmptyFolder.Fullname) -ForegroundColor Red
    }
}

Write-Host "=========================================================="

Write-Host "High-Priority Folders within $PATH :"

$NewFolders = Get-ChildItem -Path $PATH -Directory
$HighCount = 0

foreach ($folderName in $NewFolders)
{
    if (!($folderName -like "OLD"))
    {
        Write-Host $folderName
        $HighCount++
    }

}

Write-Host "=========================================================="

Write-Host ("Low Priority Folders: " + $FolderCount)
Write-Host ("Low Priority Files: " + $FileCount)
Write-Host ("High Priority Folders: " + $HighCount)

PATCHEXTRACT.PS1
Код:
<#

____     ______   ______  ____     __  __   
/\  _`\  /\  _  \ /\__  _\/\  _`\  /\ \/\ \ 
\ \ \L\ \\ \ \L\ \\/_/\ \/\ \ \/\_\\ \ \_\ \ 
\ \ ,__/ \ \  __ \  \ \ \ \ \ \/_/_\ \  _  \
  \ \ \/   \ \ \/\ \  \ \ \ \ \ \L\ \\ \ \ \ \
   \ \_\    \ \_\ \_\  \ \_\ \ \____/ \ \_\ \_\
    \/_/     \/_/\/_/   \/_/  \/___/   \/_/\/_/
                                            
                                            
____     __   __   ______  ____     ______   ____     ______ 
/\  _`\  /\ \ /\ \ /\__  _\/\  _`\  /\  _  \ /\  _`\  /\__  _\
\ \ \L\_\\ `\`\/'/'\/_/\ \/\ \ \L\ \\ \ \L\ \\ \ \/\_\\/_/\ \/
\ \  _\L `\/ > <     \ \ \ \ \ ,  / \ \  __ \\ \ \/_/_  \ \ \
  \ \ \L\ \  \/'/\`\   \ \ \ \ \ \\ \ \ \ \/\ \\ \ \L\ \  \ \ \
   \ \____/  /\_\\ \_\  \ \_\ \ \_\ \_\\ \_\ \_\\ \____/   \ \_\
    \/___/   \/_/ \/_/   \/_/  \/_/\/ / \/_/\/_/ \/___/     \/_/
                                                              
                                                              
__  __      _          __   
/\ \/\ \   /' \       /'__`\ 
\ \ \ \ \ /\_, \     /\_\L\ \
\ \ \ \ \\/_/\ \    \/_/_\_<_
  \ \ \_/ \  \ \ \  __ /\ \L\ \
   \ `\___/   \ \_\/\_\\ \____/
    `\/__/     \/_/\/_/ \/___/


================
PATCHEXTRACT.PS1
=================
Version 1.3 Microsoft MSU Patch Extraction and Patch Organization Utility by Greg Linares (@Laughing_Mantis)

This Powershell script will extract a Microsoft MSU update file and then organize the output of extracted files and folders.

Organization of the output files is based on the patch's files and will organize them based on their archicture (x86, x64, or wow64)
as well as their content-type, ie: resource and catalog files will be moved to a JUNK subfolder and patch binaries and index files will
goto a PATCH folder.

This script was developed in order to aid reverse engineers in quickly organizing patches so they can be binary diffed faster and easier.
This was especially developed with the new bulk Microsoft Kernel patches in mind.

Example output folder structure ouput would be similar to this:

C:\PATCHES\MS15-XXX\PRE
    -x86
        - x86 Binary patched files
    -x64
        - x64 binary patched files
    -WOW64
        - syswow64 binary patched files
    -JUNK
        - resource, catalog, mum, and other non-binary based patched files
    -PATCH
        - original patch, cabs and xml files from the extraction
    -MSIL
        - MSIL .NET binary patched files ***New in Version 1.1***

    Directories will automagically be organized into filename-version to remove garbage filler folder names
      
      
=============
REQUIREMENTS
=============
'expand.exe' to be present in %WINDIR%\SYSTEM32 (it is by default) - It will execute this file @ the current users permissions
A valid Microsoft MSU patch file to extract (PATCH variable)
Directory and File write/creation permissions to the PATH folder specified
      
  
======= 
USAGE
=======

Powershell -ExecutionPolicy Bypass -File PatchExtract.ps1 -Patch C:\Patches\Windows6.1-KB3088195-x64.msu -Path C:\Patches\MS15-XXX\POST\


This would extract the patch file C:\Patches\Windows6.1-KB3088195-x64.msu to the folder C:\Patches\MS15-XXX\POST\.
It will then create all the sub organization folders within C:\Patches\MS15-XXX\POST\ folder.

(Note: the optional Powershell parameters '-ExecutionPolicy Bypass' is necessary in some environments to overcome Powershell execution restrictions)

==========
ARGUMENTS
==========
-PATCH <STRING:Filename> [REQUIRED] [NO DEFAULT]
    Specifies the MSU file that will be extracted to the specified PATH folder and then organized into the x86, x64, WOW, JUNK, and BIN folders specified
    Extract command will be "expand -F:* <PATCH> <PATH>"
    Non MSU files have not been tested however if the extraction does not generate a CAB file of the same name (indicator of successful extraction of MSU files)
    the script assumes extraction failed.
  
-PATH <STRING:FolderPath> [REQUIRED] [NO DEFAULT]
    Specified the folder that the PATCH file will be extracted and organized into
    If the specified folders does not exist yet, the user will be prompted if they want to create it.
    Relative paths '.\POST' can be used but it has not extensively been tested.

    ***New in Version 1.1***
    The -PATH variable may be now omitted to expand to current directory
  

-x86 <STRING:Foldername> [OPTIONAL] [DEFAULT='x86']

    Specifies the folder name within $PATH to store x86 patch binaries
    example: -x86 32bit
  
  
-x64 <STRING:Foldername> [OPTIONAL] [DEFAULT='x64']

    Specifies the folder name within $PATH to store x64 patch binaries
    example: -x64 64bit
  
-WOW <STRING:Foldername> [OPTIONAL] [DEFAULT='WOW64']

    Specifies the folder name within $PATH to store wow64 type patch binaries
    example: -WOW sysWOW64

-MSIL <STRING:Foldername> [OPTIONAL] [DEFAULT='MSIL']

    *** New in Version 1.1***
    Specifies the folder name within $PATH to store .NET type patch binaries
    example: -MSIL DOTNET
  
-JUNK <STRING:Foldername> [OPTIONAL] [DEFAULT='JUNK']

    Specifies the folder name within $PATH to store resource, catalog, and other generally useless for diffing patch binaries
    example: -JUNK res
  
  
-BIN <STRING:Foldername> [OPTIONAL] [DEFAULT='PATCH']

    Specifies the folder name within $PATH to store extraction xml and original patch msu and cab files
    example: -BIN bin


================
VERSION HISTORY
================
I originally wrote this as an ugly batch file sometime between 2014 and 2015 as a way to organize folders but it was incomplete and buggy

Oct 15, 2015 - Initial Public Release 1.0
Oct 20, 2016 - Version 1.1 Released
                * Bug fixes handling new naming format for patch .cab files
                * Added the ability to auto-extract to the same directory as current PATCH
                * filtered output directory name format to aid in bindiffing

Oct 20, 2016 - Version 1.2 Released
                * Bug fixes handling MSIL renaming issues and collisions in renameing patch folders

Nov 7, 2016 - Version 1.25 Released
                * Added hack to handle subsequent CAB files Microsoft Added in Windows 10 Cumulative Patches - will make a better way to handle this in 1.3

March 15, 2017 - Version 1.3 Released
                * Color Change to sweet vaporwave retro 80s colors
                * Cleaned up some awful code that I must have been on some amazing substances when I wrote
                * Spent several hours making a rad ASCII Logo
                * Most importantly fixed the Sub-cab auto-extraction method that Microsoft introduced late 2016



==========
LICENSING
==========
This script is provided free as beer.  It probably has some bugs and coding issues, however if you like it or find it useful please give me a shout out on twitter @Laughing_Mantis.
Feedback is encouraged and I will be likely releasing new scripts and tools and training in the future if it is welcome.


-GLin

#>




Param
(

    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [ValidateNotNullOrEmpty()]
    [string]$PATCH = "",
  
    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [string]$PATH = "",
  
    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [string]$x86 = "x86",
  
    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [string]$x64 = "x64",
  
    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [string]$WOW = "WOW64",

    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [string]$MSIL = "MSIL",
  
    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [string]$JUNK = "JUNK",
  
    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [string]$BIN = "PATCH"
      
)

Clear-Host
$ASCIIART = @"
____     ______   ______  ____     __  __   
/\  _`\  /\  _  \ /\__  _\/\  _`\  /\ \/\ \ 
\ \ \L\ \\ \ \L\ \\/_/\ \/\ \ \/\_\\ \ \_\ \ 
\ \ ,__/ \ \  __ \  \ \ \ \ \ \/_/_\ \  _  \
  \ \ \/   \ \ \/\ \  \ \ \ \ \ \L\ \\ \ \ \ \
   \ \_\    \ \_\ \_\  \ \_\ \ \____/ \ \_\ \_\
    \/_/     \/_/\/_/   \/_/  \/___/   \/_/\/_/
                                            
                                            
____     __   __   ______  ____     ______   ____     ______ 
/\  _`\  /\ \ /\ \ /\__  _\/\  _`\  /\  _  \ /\  _`\  /\__  _\
\ \ \L\_\\ `\`\/'/'\/_/\ \/\ \ \L\ \\ \ \L\ \\ \ \/\_\\/_/\ \/
\ \  _\L `\/ > <     \ \ \ \ \ ,  / \ \  __ \\ \ \/_/_  \ \ \
  \ \ \L\ \  \/'/\`\   \ \ \ \ \ \\ \ \ \ \/\ \\ \ \L\ \  \ \ \
   \ \____/  /\_\\ \_\  \ \_\ \ \_\ \_\\ \_\ \_\\ \____/   \ \_\
    \/___/   \/_/ \/_/   \/_/  \/_/\/ / \/_/\/_/ \/___/     \/_/
                                                              
                                                              
__  __      _          __   
/\ \/\ \   /' \       /'__`\ 
\ \ \ \ \ /\_, \     /\_\L\ \
\ \ \ \ \\/_/\ \    \/_/_\_<_
  \ \ \_/ \  \ \ \  __ /\ \L\ \
   \ `\___/   \ \_\/\_\\ \____/
    `\/__/     \/_/\/_/ \/___/
"@

Write-Host $ASCIIART -ForegroundColor Magenta
Start-Sleep -s 3


if ($PATCH -eq "")
{
    Throw ("Error: No PATCH file specified.  Specify a valid Microsoft MSU Patch with the -PATCH argument")

}

if ((Split-Path $PATCH -Parent) -eq "")
{
    # First look in current working directory for the relative filename
    $CurrentDir = $(get-location).Path;
    $PATCH = $CurrentDir + "\" + $PATCH

    # if that doesnt work we look in the current script directory (less likely)
    # but hey we tried
    if (!(Test-Path $PATCH))
    {
        $scriptDir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
        $PATCH = $scriptDir + "\" + $PATCH
    }
}

if (!(Test-Path $PATCH))
{
    Throw ("Error: Specified PATCH file ($PATCH) does not exist.  Specify a valid Microsoft MSU Patch file with the -PATCH argument.")
}

if ($PATH -eq "")
{
    $PATH = Split-Path $PATCH -Parent
    write-Host ("PATH = $PATH") -ForegroundColor White
    Write-Host ("No PATH folder specified.  Will extract to $PATH folder.") -ForegroundColor White
  
}

#Bug Fix (Resolve-Path Error if invalid path was specified before the path was created)




if (!($PATCH.ToUpper().EndsWith(".MSU")))
{
    Do
    {
        $Attempt = Read-Host ("Warning: Specified PATCH file ($PATCH) is not a MSU file type. Do you still want to attempt extraction? [Y] or [N]")
    }
    Until ('Y', 'y', 'n', 'N' -ccontains $Attempt)
    if ($Attempt.ToUpper() -eq 'N')
    {
        Write-Host ("Exiting...") -ForegroundColor DarkMagenta
        Exit
    }
}

if (!(Test-Path $PATH))
{
    Do
    {
        $Attempt = Read-Host ("Warning: Specified PATH folder ($PATH) does not exist. Do you want to create it? [Y] or [N]")
    }
    Until ('Y', 'y', 'n', 'N' -ccontains $Attempt)
    if ($Attempt.ToUpper() -eq 'N')
    {
        Write-Host ("Exiting...") -ForegroundColor DarkMagenta
        Exit
    }
    else
    {
        New-Item $PATH -Force -ItemType Directory
        Write-Host "Created $PATH Folder" -ForegroundColor Cyan
    }
}

$PATCH = Resolve-Path $PATCH
$PATH = Resolve-Path $PATH

Write-Host "Patch to Extract: $PATCH" -ForegroundColor Magenta
Write-Host "Extraction Path: $PATH" -ForegroundColor Magenta
Write-Host "x86 File Storage Folder Name: $x86" -ForegroundColor Magenta
Write-Host "x64 File Storage Folder Name: $x64" -ForegroundColor Magenta
Write-Host "WOW64 File Storage Folder Name: $WOW" -ForegroundColor Magenta
Write-Host "MSIL File Storage Folder Name: $MSIL" -ForegroundColor Magenta
Write-Host "Junk File Storage Folder Name: $JUNK" -ForegroundColor Magenta
Write-Host "Orignal Patch File Storage Folder Name: $BIN" -ForegroundColor Magenta



$PATCHx86 = Join-Path -path $PATH -ChildPath $x86
$PATCHx64 = Join-Path -path $PATH -ChildPath $x64
$PATCHWOW = Join-Path -path $PATH -ChildPath $WOW
$PATCHMSIL = Join-Path -path $PATH -ChildPath $MSIL
$PATCHJUNK = Join-Path -path $PATH -ChildPath $JUNK
$PATCHCAB = Join-Path -path $PATH -ChildPath $BIN


if (!(Test-Path $PATCHx86 -pathType Container))
{
    New-Item $PATCHx86 -Force -ItemType Directory
    Write-Host "Making $PATCHx86 Folder" -ForegroundColor Cyan
}

if (!(Test-Path $PATCHx64 -pathType Container))
{
    New-Item $PATCHx64 -Force -ItemType Directory
    Write-Host "Making $PATCHx64 Folder" -ForegroundColor Cyan
}

if (!(Test-Path $PATCHWOW -pathType Container))
{
    New-Item $PATCHWOW -Force -ItemType Directory
    Write-Host "Making $PATCHWOW Folder" -ForegroundColor Cyan
}

if (!(Test-Path $PATCHMSIL -pathType Container))
{
    New-Item $PATCHMSIL -Force -ItemType Directory
    Write-Host "Making $PATCHMSIL Folder" -ForegroundColor Cyan
}

if (!(Test-Path $PATCHJUNK -pathType Container))
{
    New-Item $PATCHJUNK -Force -ItemType Directory
    Write-Host "Making $PATCHJUNK Folder" -ForegroundColor Cyan
}

if (!(Test-Path $PATCHCAB -pathType Container))
{
    New-Item $PATCHCAB -Force -ItemType Directory
    Write-Host "Making $PATCHCAB Folder" -ForegroundColor Cyan
}


$SYSPATH = Join-Path -path (get-item env:\windir).Value -ChildPath "system32"

$EXPAND = Join-Path -path $SYSPATH -ChildPath "expand.exe"


if (!(Test-Path $EXPAND))
{
    Throw ("Error: Cannot find 'Expand.exe' in the $SYSPATH folder.")
}

$ARG = '-F:* ' + '"' + $PATCH + '" ' + '"' + $PATH + '"'

Write-Host "Executing the following command: $EXPAND $ARG" -ForegroundColor Cyan

Start-Process -File $EXPAND -ArgumentList $ARG -Wait



$CABS = Get-Childitem -Path $PATH -Filter *.cab
foreach ($CAB in $CABS)
{
    Write-Host "CAB File: $CAB" -ForegroundColor White
    if (!($CAB.Name -eq "WSUSSCAN.cab"))
    {
        $CAB = Join-Path -path $PATH -ChildPath $CAB
        Write-Host "Main-Cab: $CAB" -ForegroundColor Magenta
        if (Test-Path $CAB)
        {
            $ARG = '-F:* ' + '"' + $CAB + '" ' + '"' + $PATH + '"'
            Write-Host "Executing the following command: $EXPAND $ARG" -ForegroundColor Cyan
            Start-Process -File $EXPAND -ArgumentList $ARG -Wait
            Write-Host "Moving $CAB to $PATCHCAB" -ForegroundColor Magenta
            Move-Item $CAB $PATCHCAB -Force -ErrorAction SilentlyContinue
        }
        else
        {
            Throw "Error: Patch .CAB File [$CAB] could not be located.  Patch Extraction failed - please send notification of this error to @Laughing_Mantis."
        }
    }
    else
    {
        Write-Host "Moving $CAB to $PATCHCAB" -ForegroundColor Magenta
        Move-Item $CAB $PATCHCAB -Force -ErrorAction SilentlyContinue
    }
}

#Now for subcabs we do it again
$CABS = Get-Childitem -Path $PATH -Filter *.cab
foreach ($CAB in $CABS)
{
    if (!($CAB.Name -eq "WSUSSCAN.cab"))
    {
        $CAB =  Join-Path -path $PATH -ChildPath $CAB
        Write-Host "Sub-Cab: $CAB" -ForegroundColor Magenta
        if (Test-Path $CAB)
        {
            $ARG = '-F:* ' + '"' + $CAB + '" ' + '"' + $PATH + '"'
            Write-Host "Executing the following command: $EXPAND $ARG" -ForegroundColor Cyan
            Start-Process -File $EXPAND -ArgumentList $ARG -Wait
            Write-Host "Moving $CAB to $PATCHCAB" -ForegroundColor Magenta
            Move-Item $CAB $PATCHCAB -Force -ErrorAction SilentlyContinue
        }
        else
        {
            Throw "Error: Patch .CAB File [$CAB] could not be located.  Patch Extraction failed - please send notification of this error to @Laughing_Mantis."
        }
    }
}


<# Microsoft newer patches do not follow this formula - likely an attempt to prevent
auto extraction so we need to handle scenarios where patch cab does not have the same
name as the container MSP #>





<# Nov 7th, 2016 - Looks like Microsoft does not like my tool and added new sub-CABs to make automagic patch extraction not work.
Adding an additional check to look for sub-CABs incase this becomes the new normal.
This is an absolute hack that will likely be bypassed next month.
#>



<# 1.3 Fix - Microsoft likes to put multiple .Cabs in a single MSU now....
    So we will look in the extracted contents and run extract on ALL cabs found
    except for WSUSSCAN.cab - I feel like Microsoft might put specific patches in
    sub cabs that might cause extracted files to overwrite each other - ie
    cab 1 might have binaries for specific build while cab 2 has same binary/folder name for
    different build...fingers crossed this doesnt happen
    Also Greetz to all the Microsoft Patch Team members
#>

### I must have been on some amazing substances when i wrote this next part.....utterly ridiculous
### yeah this is garbage let me rewrite this for 1.3

<# GARBAGE CODE BELOW SAVED FOR SHAMING PURPOSES
$patchCABID = "cab_" + $patchCAB + "_*.cab"
$CAB = (Get-ChildItem -Path $PATH -Filter $PatchCABID | Select-Object -First 1)
Write-Host "Debug CAB = $CAB"
if (Test-Path $CAB)
{
    $flag = "1"
}

while ($flag -eq "1")
{
    Write-Host "Subsequent CAB  $CAB detected - attempting beta extraction" -ForegroundColor Yellow
    $ARG = '-F:* ' + '"' + $CAB + '" ' + '"' + $PATH + '"'

    Write-Host "Executing the following command: $EXPAND $ARG" -ForegroundColor Cyan

    Start-Process -File $EXPAND -ArgumentList $ARG -Wait

    $patchCAB++

    $patchCABID = "cab_" + $patchCAB + "_*.cab"
    try
    {
        $CAB = (Get-ChildItem -Path $PATH -Filter $PatchCABID | Select-Object -First 1)
        if ((!(Test-Path $CAB)) -or ($CAB -eq ""))
        {
            $flag = "0"
        }
    }
    catch
    {
        $flag = "0"
    }

}
#>



$PATCHFolders = Get-ChildItem -Path $PATH -Force -ErrorAction SilentlyContinue | where {$_.Attributes -eq 'Directory'}

foreach ($folder in $PATCHFolders)
{
    if ($folder.Name.Contains(".resources_"))
    {
        Move-Item $folder.FullName $PATCHJUNK -Force
        Write-Host "Moving $folder to $PATCHJUNK" -ForegroundColor Cyan
        Continue
    }
    else
    {
        if ($folder.Name.StartsWith("x86_"))
        {
            Move-Item $folder.FullName $PATCHx86 -Force
            Write-Host "Moving $folder to $PATCHx86" -ForegroundColor Cyan
            Continue
        }
      
        if ($folder.Name.StartsWith("amd64_"))
        {
            Move-Item $folder.FullName $PATCHx64 -Force
            Write-Host "Moving $folder to $PATCHx64" -ForegroundColor Cyan
            Continue
        }
      
        if ($folder.Name.StartsWith("wow64_"))
        {
            Move-Item $folder.FullName $PATCHWOW -Force
            Write-Host "Moving $folder to $PATCHWOW" -ForegroundColor Cyan
            Continue
        }

        if ($folder.Name.StartsWith("msil_"))
        {
            Move-Item $folder.FullName $PATCHMSIL -Force
            Write-Host "Moving $folder to $PATCHMSIL" -ForegroundColor Cyan
            Continue
        }
    }
}

<# PRETTY BINDIFF OUTPUT - changes folder names from x86-microsoft-windows-filename-hash-version-garbage to filename-version #>

$PATCHFolders = Get-ChildItem -Path $PATCHx86 -Force -ErrorAction SilentlyContinue | where {$_.Attributes -eq 'Directory'}

foreach ($folder in $PATCHFolders)
{
    if ($folder -like "x86_microsoft-windows-*")
    {
        $newfolder = $folder.Name.Replace("x86_microsoft-windows-", "")
        $newname = $newfolder.Split("_")[0]
        $version = $newfolder.Split("_")[2]
        $newname = $newname + "_" + $version
        Write-Host ("Renaming $folder to $newname") -ForegroundColor Magenta
        Rename-Item -path $folder.FullName -newName ($newname)
    }
    elseif ($folder -like "x86_*")
    {
        $newfolder = $folder.Name.Replace("x86_", "")
        $newname = $newfolder.Split("_")[0]
        $version = $newfolder.Split("_")[2]
        $newname = $newname + "_" + $version
        Write-Host ("Renaming $folder to $newname") -ForegroundColor Cyan
        Rename-Item -path $folder.FullName -newName ($newname)
    }
}

$PATCHFolders = Get-ChildItem -Path $PATCHx64 -Force -ErrorAction SilentlyContinue | where {$_.Attributes -eq 'Directory'}

foreach ($folder in $PATCHFolders)
{
    if ($folder -like "amd64_microsoft-windows-*")
    {
        $newfolder = $folder.Name.Replace("amd64_microsoft-windows-", "")
        $newname = $newfolder.Split("_")[0]
        $version = $newfolder.Split("_")[2]
        $newname = $newname + "_" + $version
        Write-Host ("Renaming $folder to $newname") -ForegroundColor Magenta
        Rename-Item -path $folder.FullName -newName ($newname)
    }
    elseif ($folder -like "amd64_*")
    {
        $newfolder = $folder.Name.Replace("amd64_", "")
        $newname = $newfolder.Split("_")[0]
        $version = $newfolder.Split("_")[2]
        $newname = $newname + "_" + $version
        Write-Host ("Renaming $folder to $newname") -ForegroundColor Cyan
        Rename-Item -path $folder.FullName -newName ($newname)
    }
}

$PATCHFolders = Get-ChildItem -Path $PATCHWOW -Force -ErrorAction SilentlyContinue | where {$_.Attributes -eq 'Directory'}

foreach ($folder in $PATCHFolders)
{
    if ($folder -like "wow64_microsoft-windows-*")
    {
        $newfolder = $folder.Name.Replace("wow64_microsoft-windows-", "")
        $newname = $newfolder.Split("_")[0]
        $version = $newfolder.Split("_")[2]
        $newname = $newname + "_" + $version
        Write-Host ("Renaming $folder to $newname") -ForegroundColor Magenta
        Rename-Item -path $folder.FullName -newName ($newname)
    }
    elseif ($folder -like "wow64_*")
    {
        $newfolder = $folder.Name.Replace("wow64_", "")
        $newname = $newfolder.Split("_")[0]
        $version = $newfolder.Split("_")[2]
        $newname = $newname + "_" + $version
        Write-Host ("Renaming $folder to $newname") -ForegroundColor Cyan
        Rename-Item -path $folder.FullName -newName ($newname)
    }
}

$PATCHFolders = Get-ChildItem -Path $PATCHMSIL -Force -ErrorAction SilentlyContinue | where {$_.Attributes -eq 'Directory'}

foreach ($folder in $PATCHFolders)
{
    if ($folder -like "msil_*")
    {
        $newfolder = $folder.Name.Replace("msil_", "")
        $newname = $newfolder.Split("_")[0]
        $version = $newfolder.Split("_")[2]
        $newname = $newname + "_" + $version
        Write-Host ("Renaming $folder to $newname") -ForegroundColor Cyan
        Rename-Item -path $folder.FullName -newName ($newname)
    }

}

$Junkfiles = Get-ChildItem -Path $PATH -Force -ErrorAction SilentlyContinue


foreach ($JunkFile in $Junkfiles)
{
  
    try
    {
        if (($JunkFile.Name.EndsWith(".manifest")) -or ($JunkFile.Name.EndsWith(".cat")) -or ($JunkFile.Name.EndsWith(".mum")))
        {
            Move-Item $JunkFile.FullName $PATCHJUNK -Force -ErrorAction SilentlyContinue
            Write-Host "Moving $JunkFile to $PATCHJUNK" -ForegroundColor Magenta
            Continue
        }
      
        if (($JunkFile.Name.EndsWith(".cab")) -or ($JunkFile.Name.EndsWith(".xml")) -or ($JunkFile.Name.EndsWith(".msu")) -or ($JunkFile.Name.EndsWith("pkgProperties.txt")))
        {
            Move-Item $JunkFile.FullName $PATCHCAB -Force -ErrorAction SilentlyContinue
            Write-Host "Moving $JunkFile to $PATCHCAB" -ForegroundColor Cyan
            Continue
        }
        if ($JunkFile.Name -eq "patch")
        {
            Move-Item $JunkFile.FullName $PATCHCAB -Force -ErrorAction SilentlyContinue
            Write-Host "Moving $JunkFile to $PATCHCAB" -ForegroundColor Magenta
            Continue
        }
    }
    catch
    {
        Write-Host "Error Processing ($JunkFile.Fullname)" -ForegroundColor DarkMagenta
    }
}

Туториал v1.0 размещен тут https://xssforum7mmh3n56inuf2h73hvhnzobi7h2ytb3gvklrfqm7ut3xdnyd.onion/threads/40986/
 
Вопрос по Windows Patch Diffing.
Не всегда внутри .msu файлов лежат сами бинари, частенько там лежат так называемые дельты.

Они есть трёх видов:
  • Forward differentials (f)
  • Reverse differentials (r)
  • Null differentials (n)
Вопрос в том как с ними работать. Обычно я просто грузил VM с нужной осью, ставил снапшот, обновлялся, а потом откатывался обратно.

Но есть ведь msdelta.dll.
Автор вот этой замечательной статьи, приложил скрипт:
Python:
from ctypes import (windll, wintypes, c_uint64, cast, POINTER, Union, c_ubyte,
                    LittleEndianStructure, byref, c_size_t)
import zlib


# types and flags
DELTA_FLAG_TYPE             = c_uint64
DELTA_FLAG_NONE             = 0x00000000
DELTA_APPLY_FLAG_ALLOW_PA19 = 0x00000001


# structures
class DELTA_INPUT(LittleEndianStructure):
    class U1(Union):
        _fields_ = [('lpcStart', wintypes.LPVOID),
                    ('lpStart', wintypes.LPVOID)]
    _anonymous_ = ('u1',)
    _fields_ = [('u1', U1),
                ('uSize', c_size_t),
                ('Editable', wintypes.BOOL)]


class DELTA_OUTPUT(LittleEndianStructure):
    _fields_ = [('lpStart', wintypes.LPVOID),
                ('uSize', c_size_t)]


# functions
ApplyDeltaB = windll.msdelta.ApplyDeltaB
ApplyDeltaB.argtypes = [DELTA_FLAG_TYPE, DELTA_INPUT, DELTA_INPUT,
                        POINTER(DELTA_OUTPUT)]
ApplyDeltaB.rettype = wintypes.BOOL
DeltaFree = windll.msdelta.DeltaFree
DeltaFree.argtypes = [wintypes.LPVOID]
DeltaFree.rettype = wintypes.BOOL
gle = windll.kernel32.GetLastError


def apply_patchfile_to_buffer(buf, buflen, patchpath, legacy):
    with open(patchpath, 'rb') as patch:
        patch_contents = patch.read()

    # some patches (Windows Update MSU) come with a CRC32 prepended to the file
    # if the file doesn't start with the signature (PA) then check it
    if patch_contents[:2] != b"PA":
        paoff = patch_contents.find(b"PA")
        if paoff != 4:
            raise Exception("Patch is invalid")
        crc = int.from_bytes(patch_contents[:4], 'little')
        patch_contents = patch_contents[4:]
        if zlib.crc32(patch_contents) != crc:
            raise Exception("CRC32 check failed. Patch corrupted or invalid")

    applyflags = DELTA_APPLY_FLAG_ALLOW_PA19 if legacy else DELTA_FLAG_NONE

    dd = DELTA_INPUT()
    ds = DELTA_INPUT()
    dout = DELTA_OUTPUT()

    ds.lpcStart = buf
    ds.uSize = buflen
    ds.Editable = False

    dd.lpcStart = cast(patch_contents, wintypes.LPVOID)
    dd.uSize = len(patch_contents)
    dd.Editable = False

    status = ApplyDeltaB(applyflags, ds, dd, byref(dout))
    if status == 0:
        raise Exception("Patch {} failed with error {}".format(patchpath, gle()))

    return (dout.lpStart, dout.uSize)


if __name__ == '__main__':
    import sys
    import base64
    import hashlib
    import argparse

    ap = argparse.ArgumentParser()
    mode = ap.add_mutually_exclusive_group(required=True)
    output = ap.add_mutually_exclusive_group(required=True)
    mode.add_argument("-i", "--input-file",
                      help="File to patch (forward or reverse)")
    mode.add_argument("-n", "--null", action="store_true", default=False,
                      help="Create the output file from a null diff "
                           "(null diff must be the first one specified)")
    output.add_argument("-o", "--output-file",
                        help="Destination to write patched file to")
    output.add_argument("-d", "--dry-run", action="store_true",
                        help="Don't write patch, just see if it would patch"
                             "correctly and get the resulting hash")
    ap.add_argument("-l", "--legacy", action='store_true', default=False,
                    help="Let the API use the PA19 legacy API (if required)")
    ap.add_argument("patches", nargs='+', help="Patches to apply")
    args = ap.parse_args()

    if not args.dry_run and not args.output_file:
        print("Either specify -d or -o", file=sys.stderr)
        ap.print_help()
        sys.exit(1)

    if args.null:
        inbuf = b""
    else:
        with open(args.input_file, 'rb') as r:
            inbuf = r.read()

    buf = cast(inbuf, wintypes.LPVOID)
    n = len(inbuf)
    to_free = []
    try:
        for patch in args.patches:
            buf, n = apply_patchfile_to_buffer(buf, n, patch, args.legacy)
            to_free.append(buf)

        outbuf = bytes((c_ubyte*n).from_address(buf))
        if not args.dry_run:
            with open(args.output_file, 'wb') as w:
                w.write(outbuf)
    finally:
        for buf in to_free:
            DeltaFree(buf)

    finalhash = hashlib.sha256(outbuf)
    print("Applied {} patch{} successfully"
          .format(len(args.patches), "es" if len(args.patches) > 1 else ""))
    print("Final hash: {}"
          .format(base64.b64encode(finalhash.digest()).decode()))

Есть ли какие-нибудь ещё готовые скрипты/инструменты для работы с дельтами?
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Вопрос в том как с ними работать.

Есть ли какие-нибудь ещё готовые скрипты/инструменты для работы с дельтами?
Там ведь все по полочкам расписано... Даже цтфка есть...

Наврятли, есть еще какие-либо инструменты... Даже не так...., ааааа чем тебе API не инструмент??? В твоем распоряжение есть, как старый API - PatchAPI, так и новый - MSDelta.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Есть ли какие-нибудь ещё готовые скрипты/инструменты для работы с дельтами?
Если в контексте патч-диффинга, то зачем это нужно? Разве что искать какие-то silent-фиксы, информации о которых нигде в паблике нет. Для всего остального хостовая десятка, которая обновляется и необновляемая виртуалка, на случай, если нужно позапускать на ней полуPoCи. Искать кандидатов на анализ можно по временным меткам в системной дире или опираться на паблик инфу с того же Security Update Guide. Статью эту читал давно и баловался скриптами, была даже мысль написать гуй под это дело, в итоге так и не понял зачем это нужно на практике. Разве что для какой-то статистики. Другое дело, что дельта-файлы теоретически можно использовать как вектор атаки для инъекции кода в ядро, вот это уже интересно. Примитивный сценарий - пересобрать cab с патченной forward-дельтой для ntoskrnl.exe (при наличии уязвимости в формате и/или цифровой подписи кода) и вручную обновиться через dism.exe или его аналоги.
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Effective Patch Analysis for Microsoft Updates (Power of Community 2016)
Every Patch Tuesday, many people get busy. Whether you are an IT administrator who needs to deploy patches or a security researcher who wants to learn what vulnerabilities were fixed (or a pentester who wants to develop 1-day exploits), you have to maintain and manage released patches -- especially if you have to do it for multiple systems.

In this talk, we take a look at the general process of patch analysis. We walk through each step from downloading the patch to a weaponized exploit. For the case study, we perform the analysis for CVE-2016-0189 (vbscript.dll) and jscript9.dll security bug fixed in MS16-063.

At Theori, we built a system called 'Petch' (_P_atch + F_etch_) that can help you manage Microsoft's patches/updates more effectively. The system will expedite the patch analysis by providing the database of the updates of interest, as well as the symbol files for the executable files. Petch is not a cloud service, but we will open source shortly after the conference, so it can be set up locally.

While we only cover browser vulnerabilities and exploits, the techniques and tools can be used for variety of things such as kernel drivers.
 
Форумчане, есть такой вопрос. Решился я взяться за патчдиффинг, но возникли трудности в лице невозможности нормально найти исходный и патченый файл. Распаковать msu получается, но как узнать какой именно из dll-ок был затронут, а также как найти предыдущую, не патченую, версию этой dll? Прошу поделиться своими способами поиска тех кто пишет 1-day экспы
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Microsoft патчит много. Самый проcтой и удобный способ, на мой взгляд, держать виртуальную машину с относительно старой версией и другую вм либо хост для обновлений. Слишком старую держать смысла нет, т.к. патчей будет очень много и трудно будет выискивать релевант. Все разреверсить ты все равно не сможешь руками, кода много и не каждый патч - это уязвимость. Иногда код просто соптимизирован, где-то добавлены новые функции и убраны старые. И это не говоря про то, что нужно понять как стригеррить баг, что подчас бывает сложнее его обнаружения и затратней по времени. Понять что вероятно патчилось можно по дате файлов в c:\windows\system32, c:\windows\system32\drivers и т.д. и уже по вкусу брать интересующие модули. Иногда обе версии файлов можно найти на https://files.ninja/msft/latest. Также вспомогательную информацию об уязвимых модулях можно найти в твиттере и в деталях MSRC Update Guide.
 
Если возникает желание подиффить что-то, делаю 2 уязвимые виртуалки, а потом на одну накатываю нужный айдейт. Уязвимую версию беру тут: https://uupdump.net/, но некоторые старые версии не скачиваются
Потрошу файлы, пишу триггеры для интересных функций и в динамике изучаю на этих же виртуалках.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Пожалуйста, обратите внимание, что пользователь заблокирован
Возможно у кого-то есть рациональное объяснение двум вещам.

1. Почему мелкософт кладет в обновления кучу патчей для старых версий файлов? Из 300+ патчей последними исправлениями являются только 19 файлов (это только драйвера, .dll, .exe будут идти на тысячи).

2. Почему в патчах номер UBR отличается от представленного на сайте, лол?

1734190913374.png
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Удивительное и невероятное в декабрьском бюллетене мелкософта.

1734638186044.png


Только я не понял почему от версии к версии в петухоне (начиная с 3.6) патчат уязвимость почти 20 летней давности. Какая-то загадка от Жака Фреско.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Только я не понял почему от версии к версии в петухоне (начиная с 3.6) патчат уязвимость почти 20 летней давности. Какая-то загадка от Жака Фреско.
Видимо существует какая-то проблема совмести со старым кодом в путях. Так как CVE-2007-4559 это path traversal и они все не как запатчить не могут.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Казалось бы мелочь, но как программно выдернуть ссылку на загрузку обновления, например, из https://catalog.update.microsoft.com/Search.aspx?q=KB5025229 ? Для получения ссылки требуется взаимодействие с браузером, ссылка непредсказуема.
Бурпом глянул запросы и там куча какой-то х#йни летит до того как получится актуальный ответ с ссылкой.


P.S. Разобрался. Сначала надо распарсить страницу и получить id нужного обновления.
Потом с этим id сделать запрос.

Код:
POST /DownloadDialog.aspx HTTP/1.1
Host: catalog.update.microsoft.com
User-Agent: <redacted>
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 63

updateIDs=[{"updateID":"b5e67e30-a821-4640-84df-9700e9fe2d46"}]
]

В ответе будет ссыль

Код:
downloadInformation[0].files[0].url = 'https://catalog.s.download.windowsupdate.com/d/msdownload/update/software/secu/2023/04/windows10.0-kb5025229-x86_00753b2d80cf3356dbcc47707823d9d08331ea3a.msu';

Вопрос к тем, у кого стоят январские обновления. Может кто чекнуть версию файла tapisrv.dll в C:\Windows\system32\ или возможно другие бинари с префиксом tapi*.
Предполагаю, что патч был в этой .dll, но мой скрипт ничего такого не вернул из распакованного KB. Видимо мелкософт опять выпустил бюллетень, но исправления выпустить забыл. Могу ошибаться.

1736974110845.png
 
Последнее редактирование:


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх