Стеклянная призма, расколотая надвое на чёрном антистатическом коврике. Линия разлома обнажает внутренние узоры, напоминающие граф потока управления с одним светящимся красным узлом.


В июне 2023 года Microsoft закрыла CVE-2023-29361 - use-after-free (CWE-416) в драйвере Cloud Files Mini Filter (cldflt.sys), CVSS 7.0 (HIGH), вектор CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H. Advisory содержал одну строку: «Elevation of Privilege Vulnerability». Ни PoC, ни root cause analysis, ни указания на конкретную функцию. Одна строка - и молчание.

Два файла с Winbindex, экспорт через BinExport в Ghidra, сортировка по similarity в BinDiff - через 40 минут изменённые базовые блоки показали, где объект освобождался до повторного использования. Публичные технические разборы (без PoC) появились позже. А diff уже всё рассказал.

Это и есть patch diffing - рабочий инструмент для n-day research, когда vendor выпустил патч, а защитники ещё не понимают, что именно было исправлено. И пока они не понимают - окно открыто.

Место patch diffing в цепочке атаки и анализ 1-day уязвимостей​

Patch diffing занимает конкретную позицию в исследовательском workflow и напрямую связан с тактиками MITRE ATT&CK. На стороне атакующего это этап Resource Development: разработка эксплойтов (T1587.004) и получение информации об уязвимостях (T1588.006). Результат patch diffing - понимание root cause, которое конвертируется в эксплойт для Exploitation for Privilege Escalation (T1068), Exploit Public-Facing Application (T1190), Exploitation for Client Execution (T1203) или Exploitation of Remote Services (T1210). Куда именно - зависит от класса уязвимости и attack surface. Подробнее - в нашем статье о cve эксплойт разработка.

Цепочка от патча до эксплойта:
  1. Vendor публикует security update (Patch Tuesday, Android Security Bulletin, USN/DSA)
  2. Patch diffing: извлечение уязвимого и исправленного бинарника, бинарное сравнение функций, изоляция security-relevant изменений
  3. Root cause analysis: определение класса уязвимости (OOB write, UAF, integer overflow), input surface, достижимости из user space
  4. PoC development: минимальный триггер для подтверждения exploitability
  5. Exploit development или reporting через responsible disclosure
Между шагами 1 и 5 - patch gap. Окно, в котором уязвимый бинарь крутится на непропатченных системах, а информация для эксплуатации уже доступна через diff. Для исследователя это рабочее время. Для защитника - риск, который растёт с каждым днём без обновления.

Три рабочих сценария:
  • 1-day exploit development. Патч вышел, публичного эксплойта нет. Diff даёт root cause и input surface - основу для PoC. Применимо к Windows Patch Tuesday, Android Security Bulletin, Linux kernel stable updates. [Внешний и внутренний пентест, red team]
  • Variant analysis (поиск 0-day). Патч закрывает одну уязвимость, но паттерн ошибки повторяется в соседних функциях. Как показали исследования Mateusz Jurczyk из Google Project Zero, win32k-подсистема Windows - характерный пример: систематический анализ обработчиков приводил к обнаружению целых серий уязвимостей.
  • Тренировка reverse engineering. Patch diffing даёт одновременно цель (понять патч) и ограничение области - несколько изменённых функций вместо всего бинарника. Переход от CTF к реальному ПО через patch diffing - один из самых коротких путей.

Инструменты patch diffing: от BinDiff до Diaphora и PatchDiff​

1780394205975.webp

Требования к окружению​

  • ОС: Windows 10/11, GNU/Linux (Ubuntu 22.04+) или macOS - BinDiff и Ghidra работают на всех трёх; IDA Pro (для Diaphora) - аналогично
  • RAM: минимум 8 ГБ; для крупных бинарников (ядро Windows, Android system libraries) - 16 ГБ, иначе будете долго смотреть на прогресс-бар
  • Дисассемблер: IDA Pro 7.5+ с Python 3 (Diaphora, PatchDiff2) или Ghidra 10.x+ (BinDiff через BinExport)
  • BinDiff: v8+, бесплатный, closed-source, Google; требует BinExport (Ghidra Extension или IDA plugin)
  • Diaphora: текущая версия с GitHub (joxeankoret/diaphora), open-source, активно поддерживается
  • Сеть: offline-работа полностью поддерживается; интернет нужен только для скачивания бинарников (Winbindex, Microsoft Symbol Server)
ИнструментДисассемблерТип matchingПреимуществаОграниченияКогда использоватьСтатус
BinDiffIDA Pro, GhidraStructural (CFG + call graph)Скорость, стабильность на больших бинарях, наглядная визуализация CFGClosed-source, слабо работает с renamed/обфусцированными функциямиПервый проход, быстрая сортировка по similarityАктивный, Google
DiaphoraIDA Pro (основной), Ghidra, Binary Ninja (экспериментально)Heuristic + fuzzy + graph isomorphismOpen-source, скриптуемость, batch diffing, custom heuristics, экспорт в SQLiteТребует IDA Pro, медленнее BinDiff на крупных файлахГлубокий анализ, stripped бинари, автоматизацияАктивный, GitHub
PatchDiff2IDA ProSignature-based + CFGЗаточен на patch analysis, простNicolas Pouvesle (Tenable), поддержка прекращена, последние версии для устаревших IDALegacy-задачи, если нет BinDiff/DiaphoraЗаброшен
ghidriffGhidraFuzzy matching + similarity scoringБесплатный, CLI для автоматизации, CI-интеграцияМенее зрелый, документация скуднаяBatch-обработка, автоматизация в пайплайнеАктивный, GitHub
QBinDiffStandaloneNP-hard network alignment, 33 feature vectorsПолная программируемость, тюнинг метрикЭкспериментальный (Quarkslab, 2023), малая user baseFirmware, нишевые архитектурыАктивный

В работе выбор определяется задачей: BinDiff - первый проход (быстро показать, какие функции изменились), Diaphora - второй проход (копнуть глубже в кандидатов, особенно если BinDiff промахнулся или бинарь stripped). Оба работают в связке, и это не перестраховка - это рабочий протокол.

Уязвимость затрагивает Windows 10 21H2/22H2, Windows 11 21H2/22H2, Windows Server 2022. Локальный доступ, высокая сложность атаки (AC:H), нужны минимальные привилегии (PR:L), взаимодействие пользователя не требуется (UI:N). EPSS 0.0129 (percentile 0.7995) - выше медианы, заметная вероятность эксплуатации. CISA SSVC: Track (мониторить), exploitation - none, technical impact - total.

Получение уязвимого и исправленного бинарника

Для Windows основной источник - Winbindex (winbindex.m417z.com). Сервис отслеживает версии системных файлов и даёт ссылки на скачивание напрямую с серверов Microsoft.

Workflow для cldflt.sys:
  1. Открыть winbindex.m417z.com/?file=cldflt.sys, отфильтровать по Windows 10 22H2
  2. Скачать как cldflt_patched.sys
  3. Скачать как cldflt_vuln.sys
Для других платформ: GNU/Linux - бинарники из security-репозиториев дистрибутива (.deb/.rpm); Android - factory images или OTA с developers.google.com; macOS - IPSW-файлы или extracted dyld shared cache.

Бинарное сравнение функций через BinDiff​

Workflow Ghidra + BinExport + BinDiff:
  1. Загрузить оба бинарника в Ghidra (отдельные программы в проекте)
  2. Для Windows-драйверов - загрузить символы: File -> Load PDB File -> Advanced -> Search All (поиск на серверах Microsoft)
  3. Перебазировать на 0x0: Window -> Memory Map -> иконка Home -> ввести 0
  4. Запустить автоанализ: Analysis -> Auto-Analyze с дефолтными настройками, дождаться завершения
  5. Экспортировать: File -> Export Program -> формат Binary BinExport (V2) for BinDiff
  6. Повторить шаги 1-5 для второго бинарника
Код:
bindiff --primary cldflt_vuln.BinExport --secondary cldflt_patched.BinExport -o diff_result
Результат открывается в GUI (bindiff -ui) или анализируется программно через BinDiff API.

Интерпретация diff: на что смотреть в графе​

Открываем Matched Functions, сортируем по Similarity по возрастанию. Функции с similarity ниже 1.0 - кандидаты. Но не все: часть - обновления библиотек, отладочные изменения, stack canaries. Шум неизбежен, и его надо уметь отсеивать.

Фильтры первого прохода:
  • Similarity < 0.95 - функция изменилась существенно
  • Confidence > 0.7 - BinDiff уверен в сопоставлении
  • Basic blocks changed > 0 - есть структурные изменения в CFG
После фильтрации для CVE-2023-29361 остаётся несколько функций. Открываем side-by-side в графовом представлении: слева - уязвимая версия, справа - исправленная. Изменённые базовые блоки подсвечены. Ищем:
  • Добавленные проверки (bounds check, null check, reference counting)
  • Удалённые или перемещённые участки кода
  • Изменения в порядке вызовов free/allocate - характерная сигнатура UAF-патча
Для use-after-free типичный патч: добавлена проверка валидности указателя перед dereference, или изменён порядок операций free/use, или вставлен InterlockedIncrement (reference count) перед передачей объекта в другой контекст. В графе это один-два новых базовых блока с условным переходом непосредственно перед вызовом, который использовал уже освобождённый объект. Увидеть это в CFG - дело нескольких минут, если знаешь, что искать.

Паттерны анализа патчей безопасности: сигнатуры security fix​

1780398153241.webp

Каждый класс уязвимости оставляет характерный отпечаток в diff. Зная эти паттерны, время анализа сокращается с часов до минут.
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме

Use-after-free (CWE-416). CVE-2023-29361. UAF-патчи содержат одно из трёх изменений: добавление ref_count++ перед передачей указателя, перемещение вызова free после последнего использования объекта, или null-проверка указателя перед dereference после функции, которая может освободить объект.

CVE-2019-8606. Патч добавил improved validation символьных ссылок (по описанию Apple), что в бинарном diff проявляется как новые проверки пути или типа объекта перед использованием. Хотя CVE-2019-8606 классифицирован как CWE-362, конкретный патч - это validation fix, а не добавление lock-примитивов. Такое бывает: формальная классификация и реальный патч расходятся.

Сводная таблица:

Класс (CWE)Типичный патч в diffСигнал в BinDiffПример CVE
OOB write (CWE-787)Bounds check перед memcpy/writeНовый block с compare + conditional jumpCVE-2023-21273
Integer overflow (CWE-190)Overflow check перед аллокациейBlock с MAX-constant comparisonCVE-2023-21241
Use-after-free (CWE-416)Изменён порядок free/use или добавлен refcountПерестановка блоков, новый call к ref-функцииCVE-2023-29361
Race condition (CWE-362)Добавлена синхронизация (lock/mutex) или validationНовые call-инструкции к lock-функциям или проверки валидностиCVE-2019-8606 (validation fix)

CISA SSVC классифицирует CVE-2023-21273, CVE-2023-21241 и CVE-2023-29361 как Track (мониторить): exploitation - none, automatable - no, technical impact - total. Низкий EPSS (0.0002–0.0129) подтверждает: без patch diffing эти уязвимости остались бы «тёмными» - формально закрытыми, но технически непонятными для защитников. Advisory сказал «fixed», а что именно fixed - разбирайтесь сами.

BinDiff vs Diaphora: бинарный diff в двух парадигмах​

1780398384383.webp

Инструменты используют принципиально разные подходы к сопоставлению, и эта разница критична на практике.

BinDiff строит CFG и call graph, использует MD-index и фингерпринты базовых блоков для матчинга. Подход восходит к работе Halvar Flake 2004 года о structural comparison of executable objects - одной из первых формализаций проблемы. BinDiff быстр и стабилен на бинарях с символами.

Проблемы начинаются, когда компилятор переупорядочивает блоки (PGO), функция инлайнится после LTO, или регистровая аллокация меняется (RAX вместо RDX для той же переменной). BinDiff в таких случаях даёт false match или оставляет функцию в unmatched. И ты сидишь, гадаешь - это security fix или компилятор поиграл в тетрис.

Diaphora комбинирует exact match (хеш-сравнение), fuzzy matching (набор нечётких признаков), graph isomorphism и специализированные эвристики для stripped бинарей. Промежуточные данные экспортируются в SQLite - можно писать SQL-запросы поверх результатов, строить кастомные фильтры и автоматизировать batch-обработку.

Ключевое архитектурное отличие - расширяемость. В Diaphora можно добавлять custom heuristics для конкретного таргета, фильтровать экспортируемые функции по паттернам, делать partial diffing (сравнение только конкретных функций) и писать собственные инструменты поверх Diaphora как библиотеки. Для исследователя, который регулярно анализирует патчи одного продукта (ядро Windows, Android system server), это меняет дело: один раз настроенные heuristics ускоряют каждый последующий анализ.

При анализе патчей Android Bluetooth-стека (CVE-2023-21273, CVE-2023-21241) картина характерная: BinDiff корректно сопоставляет функции с символами, но на stripped Bluetooth-стеке промахивается. Diaphora в аналогичных сценариях показывает лучшую точность за счёт fuzzy matching, но работает медленнее. Компромисс, к которому можно привыкнуть.

Рабочий протокол: BinDiff для первого прохода (10-15 минут на экспорт + diff, сортировка по similarity, выделение 5-10 кандидатов). Diaphora - для углублённого анализа конкретных функций, если BinDiff не дал однозначного результата или бинарь stripped.

[Применимо: оба инструмента работают для Windows, GNU/Linux, macOS, Android. BinDiff - через Ghidra (бесплатно) или IDA Pro. Diaphora - основная поддержка IDA Pro, экспериментальная поддержка Ghidra и Binary Ninja в версиях 3.x+]

Ограничения бинарного анализа уязвимостей и фильтрация шума

Security fix - далеко не единственное изменение в обновлённом бинарнике. Источники шума:
  • Non-security баг-фиксы и фичи. В Windows Patch Tuesday один модуль часто получает несколько патчей одновременно. Для Android Security Bulletin - десятки компонентов обновляются в одном билде. Всё это попадает в diff.
  • Изменения компилятора. Обновление тулчейна (MSVC, clang) меняет instruction selection, register allocation, порядок блоков. Тысячи «изменённых» функций, семантически идентичных. Самый раздражающий источник шума.
  • Stack canaries и массовый hardening. Добавление /GS в MSVC или -fstack-protector в gcc меняет пролог/эпилог каждой функции.
  • LTO и PGO. Link-Time Optimization и Profile-Guided Optimization радикально перестраивают layout бинарника.
Стратегии фильтрации:
  1. Начинать с модулей из advisory. Microsoft указывает «Cloud Files Mini Filter Driver» - diff только cldflt.sys, не всю ОС
  2. Отсекать similarity = 1.0. 100% совпадение - функция не менялась
  3. Фокус на малом числе изменённых блоков. Security fix - это 1-5 базовых блоков. 50+ блоков - скорее refactoring
  4. Искать паттерны из таблицы выше: bounds check, null check, overflow check, lock primitives
  5. Использовать символы. PDB для Windows, DWARF для GNU/Linux. Для Apple Objective-C имена методов сохраняются в бинарнике runtime'ом - это упрощает сопоставление
Где patch diffing буксует или врёт:
  • Полная перекомпиляция с другой оптимизацией. Переход с -O0 на -O2 меняет всё: inlining, loop unrolling, dead code elimination. Security fix неотличим от тысяч compiler-induced изменений. Тут diff бесполезен.
  • Cross-architecture. Сравнение ARM и x86 версий требует специализированных инструментов (QBinDiff, DeepDiff с embedding-based подходом). BinDiff и Diaphora на это не рассчитаны.
  • Обфускация. Control flow flattening и opaque predicates ломают structural matching. Если бинарь прошёл через обфускатор - готовьтесь к ручной работе.
  • Распределённый патч. Исправление рассыпано по нескольким call sites после LTO - нет единой «патченной функции». По данным ряда исследований LLM-агентов для patch analysis, значительная часть неудач происходит именно здесь - бинарный диффер не включает security-relevant функцию в набор кандидатов, и модель в принципе не может её увидеть.
Для Linux-ядра дополнительная боль: security-фиксы попадают в upstream без маркировки CVE, как обычные баг-фиксы с формулировкой «fix bounds check». Дистрибутивы собирают их в бинарные пакеты, и diff между двумя версиями .deb - единственный путь к root cause. Исследования LLM-агентов для бинарного анализа показывают, что точность локализации security-relevant функции при работе с бинарными артефактами без advisory остаётся ограниченной - и узкое место зачастую не LLM-модель, а качество бинарного diff на этапе формирования списка кандидатов.

Заключение

Многие говорят о patch diffing как о навыке, который «надо бы освоить». Реальный workflow от скачивания бинарника до root cause отработан у единиц. Причина простая: первые две-три попытки выдают тысячи изменённых функций, нет понимания куда смотреть, и человек откладывает тему до следующего Patch Tuesday. Который тоже проходит мимо.

А зря. Patch diffing - навык с самой быстрой отдачей во всём vulnerability research. Не fuzzing, где месяцами строишь harness и ждёшь crash. Не аудит исходников, где нужно прочитать миллион строк. Здесь - 30-60 минут на конкретную цель с гарантированным результатом: патч существует, уязвимость в нём точно есть, задача - найти где.

Через год-два LLM-агенты заберут тривиальную часть этой работы - первичный triage и ранжирование функций-кандидатов. Но финальный шаг - прочитать граф, понять семантику изменения, оценить exploitability - останется за аналитиком. Модели видят синтаксис diff, но не понимают, почему bounds check в одном контексте означает remote code execution, а в другом - просто hardening. Тот, кто нарабатывает этот навык руками сейчас, через два года будет не конкурировать с автоматизацией, а управлять ею.

Попробуйте взять любой CVE из июньского Patch Tuesday 2023, стянуть бинарники с Winbindex и прогнать через BinDiff по описанному workflow. Первый раз будет больно. Второй - уже нет. На WAPT эту цепочку проходят в течение двух модулей с лабами.
 
Последнее редактирование модератором:
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

Похожие темы

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab