LLM-агент, ограниченный локальными бинарными артефактами - без CVE-описания, без исходного патча, без changelog - локализовал security-relevant функцию в 10 из 20 реальных Ubuntu .deb-пакетов и корректно определил root-cause класс уязвимости в 11 из 20 случаев. Это результаты исследования Patch2Vuln с arxiv. За два года интеграции LLM в рабочий процесс patch diffing ядра Linux я убедился: основное узкое место - не модель, а бинарный диффер. Patch2Vuln подтверждает это цифрами: 6 из 20 неудач случились до того, как LLM вообще увидел данные - на этапе извлечения и ранжирования функций.
Бинарный патч как единственный артефакт для n-day research
Когда дистрибутив Linux выпускает security-обновление, появляется окно, в котором уязвимый и исправленный бинарники доступны одновременно. Для n-day vulnerability research эта пара ELF-файлов - основной источник информации. Не advisory на NVD (которое зачастую содержит одно предложение), не коммит в upstream - а два бинарника, старый и новый. Подробнее - в нашем подробном разборе бинарный анализ уязвимостей.В upstream ядра Linux действует культура «bugs are bugs»: security-фиксы часто попадают в публичные коммиты без явной маркировки. Коммит может содержать формулировку «fix bounds check» или «avoid in-place operation» без указания на CVE-идентификатор. Дистрибутивы - Ubuntu, Debian, RHEL - собирают эти фиксы в бинарные пакеты, и diff между двумя версиями .deb или .rpm становится первичным артефактом для patch-based vulnerability discovery.
Задача формулируется прямо: получив пару бинарных пакетов (vulnerable и patched), определить, какая функция изменена по причинам безопасности, какой класс уязвимости она закрывала, через какой input surface достижим уязвимый код, и что в поведении программы отличается между версиями. Вручную это занимает от часов до недель - зависит от размера diff и количества функций-кандидатов. Patch2Vuln проверяет, насколько глубоко LLM-агент может автоматизировать восстановление уязвимостей из патчей при полном отсутствии вспомогательной информации.
Работа намеренно исключает из входных данных агента: CVE-страницу, security advisory дистрибутива (USN), исходный патч, package changelog, публичный PoC и веб-доступ. Единственный источник - бинарные артефакты. Это моделирует реальный сценарий: пакет обновлён, но advisory ещё не опубликован или намеренно лаконичен.
Архитектура Patch2Vuln: pipeline и agent loop
Patch2Vuln - не новый бинарный диффер и не очередная LLM-обёртка. Система проверяет, может ли агент оркестрировать существующие инструменты binary analysis и трансформировать сырой вывод diff в структурированное объяснение уровня уязвимости.Pipeline работает в два этапа: локальный бинарный diff и агентский цикл рассуждений.
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Agent Loop: от сырого diff до структурированного аудита
Агент получает досье на каждую функцию-кандидата и проходит три стадии. Каждая порождает отдельный артефакт.Preliminary Audit. На основе статического анализа - декомпилированного diff, символов, строк, call context - агент формирует первичную гипотезу: какой класс уязвимости закрыт патчем, через какой input surface достижим уязвимый код, какова степень уверенности. Выход - структурированный JSON плюс Markdown, пригодные для машинной и человеческой обработки.
Bounded Validation Plan. Агент формулирует конкретный план проверки гипотезы: входные данные для старого и нового бинарей, ожидаемые различия в поведении - crash, sanitizer-сигнал, отличие в выводе. Валидация ограничена локальным выполнением в Docker. Никакого сетевого взаимодействия, shellcode или exploit chains - система явно не генерирует эксплуатационный код.
Final Audit. Интегрирует результаты валидации с предварительным аудитом. Если валидация подтвердила гипотезу (старый бинарь падает на подготовленном вводе, новый - нет), уверенность повышается. Если нет - агент снижает confidence или пересматривает root-cause класс.
Концептуальная структура финального аудита для случая tcpdump:
JSON:
{
"patch_family": "filter_file_bounds_check",
"root_cause_class": "out-of-bounds-read",
"input_surface": "crafted BPF filter file via -F flag",
"confidence": "medium-high",
"static_evidence": "bounds check added in read_filter()",
"validation_result": "old crashes on oversized filter; new rejects"
}
Результаты бенчмарка: 25 пар Ubuntu .deb
Patch2Vuln оценён на 25 Ubuntu .deb package pairs: 20 реальных security-обновлений и 5 negative controls (пакеты без security-фиксов). Каждая пара вручную верифицирована против ground truth - исходного патча и бинарного маппинга функций. Не synthetic benchmark - реальные обновления из Ubuntu security pipeline.Агрегированные метрики:
- Локализация патча: security-relevant функция идентифицирована в 10 из 20 security-пар (50%)
- Root-cause класс: корректно определён в 11 из 20 (55%) - в одном случае root cause определён верно без точной локализации функции, через косвенные признаки в call graph
- Negative controls: все 5 корректно классифицированы как «unknown», ни одного false positive, ни одного сгенерированного validation differential
- Behavioral validation: 2 из 20 пар (обе - tcpdump) получили минимизированный old/new behavioral differential - реальное, воспроизводимое различие в обработке конкретного ввода
- 6 пар: отказ до начала рассуждений модели. Бинарный диффер или ранкер не включил security-relevant функцию в набор кандидатов. LLM в принципе не мог её увидеть - нечего анализировать
- 1 пара: ошибка экспорта контекста. Функция попала в кандидаты, но декомпилированный контекст был урезан или некорректно передан агенту
- 3 пары: ошибки рассуждения модели. Функция видна, контекст передан, но агент неверно интерпретировал diff
-O2, распределена по нескольким call sites после LTO, или замаскирована массовыми изменениями - например, добавлением stack canaries ко всем функциям.tcpdump (bionic) - агент успешно идентифицировал уязвимость в обработке filter-файлов. Декомпилированный diff показал добавление bounds check в функции чтения BPF-фильтра. Root-cause определён как out-of-bounds read, а bounded validation подтвердила: старый бинарь читал за границами буфера на специально подготовленном вводе, новый корректно отвергал.
Expat - сильная статическая реконструкция. Агент верно определил root-cause класс в XML-парсере, но не сумел построить работающий trigger. Для парсеров это типичная история: уязвимый путь требует специфической комбинации вложенных XML-конструкций, которую сложно сгенерировать автоматически. Статический аудит корректен, behavioral validation - нет.
libarchive - локализация успешна, но финальный root-cause класс консервативен: «possible memory safety issue» вместо конкретного CWE-типа. Для n-day research осторожность оправдана. Conservative final class лучше, чем false positive с high confidence. Я бы тоже так написал в отчёте.
LLM-powered patch diffing в индустрии: подход Bishop Fox
Patch2Vuln - не единственная попытка натравить LLM на бинарный анализ уязвимостей. Параллельное исследование от Bishop Fox использует другой стек и другую методологию, что позволяет выделить инвариантные паттерны и специфические ограничения каждого подхода.Bishop Fox берёт Binary Ninja для декомпиляции и BinDiff для сравнения вместо связки Ghidra/Ghidriff. LLM получает два промпта: первый - декомпилированные функции с запросом на именование и описание, второй - текст vendor advisory плюс результаты первого промпта с запросом на итеративное ранжирование функций по релевантности.
Принципиальное отличие: Bishop Fox даёт агенту vendor advisory. Patch2Vuln намеренно работает без него. В реальном n-day research оба сценария встречаются: USN/RHSA/DSA доступны чаще, чем кажется, но зачастую содержат минимум технических деталей.
Bishop Fox протестировали workflow на четырёх CVE с CVSS 9.4+ и тремя моделями (Claude Haiku 3.5, Claude Sonnet 3.7, Claude Sonnet 4):
- Information disclosure (27 изменённых функций): все три модели разместили уязвимую функцию в Top 5 в каждом прогоне - эталонный результат
- Format string injection (134 функции): Sonnet 3.7 и 4 - Top 5 в 100% случаев, Haiku провалился полностью
- Authorization bypass (1400+ функций): Sonnet 3.7 показал приемлемый результат, но средняя стоимость - $35 за тест
- Stack buffer overflow (708 функций): все три модели провалились. Причина - крайне лаконичный advisory и шум от массового добавления stack canaries в diff. Даже после фильтрации canary-изменений промптом только Haiku 3.5 вышел на Top 25 в 7 из 9 прогонов
| Критерий | Patch2Vuln | Bishop Fox | Ручной reverse engineering |
|---|---|---|---|
| Инструменты diff | Ghidra + Ghidriff | Binary Ninja + BinDiff | IDA/Ghidra + BinDiff/Diaphora |
| Входные данные LLM | Только бинарные артефакты | Бинарные артефакты + vendor advisory | Весь доступный контекст |
| Стоимость | Compute для Ghidra + LLM inference | До $35/тест (1400+ функций) | Часы-недели рабочего времени |
| Когда применимо | Advisory недоступен, массовый триаж | Advisory доступен, targeted analysis | Multi-function патчи, kernel modules |
| Когда не работает | Security-функция не попала в diff ranking | Скупой advisory + шум в diff | Дефицит времени и экспертизы |
| Behavioral validation | Встроено (bounded local) | Вне scope | Полная свобода (QEMU, pwndbg) |
Ускорение disclosure window: почему автоматизация patch diffing критична
Весной этого года два кейса в ядре Linux показали, как сжимается промежуток между публикацией коммита и пониманием его security-значения.Описание NVD указывает на реверт коммита в
algif_aead, устраняющий in-place операцию при обработке AEAD. CVE добавлен в CISA KEV как actively exploited. Суть: взаимодействие интерфейса AF_ALG и системного вызова splice() при in-place операции в AEAD на данных из разных mappings создавало потенциал для нежелательной модификации данных. Page cache - общий системный кэш; in-place операция на данных из разных mappings создавала потенциал для порчи кэшированных страниц. Детали возможной эксплуатации в публичных источниках ограничены.Серия связанных фиксов splice/SKBFL_SHARED_FRAG в сетевой подсистеме: CVE-2026-43284 (xfrm/ESP-in-UDP, CVSS 8.8 HIGH, CWE-123 Write-what-where Condition, вектор
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H) и CVE-2026-43500 (rxrpc, CVSS 7.8 HIGH, CWE-787 Out-of-bounds Write). Обе связаны с тем, что splice() через __ip_append_data прикрепляет страницы из pipe к skb, а обработчики xfrm/ESP-in-UDP и rxrpc не проверяют флаг SKBFL_SHARED_FRAG и модифицируют shared-страницы. Публичных PoC для этих CVE на момент написания не обнаружено.Фиксы в upstream выглядят как «avoid in-place decrypt on shared skb frags» или «revert to operating out-of-place». Чтобы разобрать такой коммит вручную, нужны часы работы аналитика, который знает крипто-подсистему ядра и механику splice/page cache. LLM-agent меняет экономику этого процесса в трёх направлениях.
Массовый мониторинг коммитов дешевеет. Pipeline может собирать diffs по подсистемам, классифицировать security-relevance и маршрутизировать подозрительные изменения на человека. Модель не обязана быть точной - достаточно уменьшить стог сена.
Variant analysis (поиск аналогичных паттернов в соседних подсистемах) становится доступнее. Нашли «splice + in-place AEAD = page cache corruption» в algif_aead? LLM неплохо справляется с поиском того же structural pattern в xfrm, rxrpc и остальных потребителях splice.
Параллельное независимое обнаружение одной уязвимости разными командами - известный паттерн в kernel security - становится ещё вероятнее.
Ограничения: где автоматический анализ бинарных патчей не работает
Patch2Vuln честно фиксирует ограничения, и для практикующего vulnerability researcher они принципиальны.Binary-diff coverage - главный bottleneck. Если компилятор агрессивно инлайнит функцию, меняет layout кода из-за LTO (Link-Time Optimization), или security-fix распределён по нескольким translation units - диффер может не выделить ключевое изменение. 6 из 20 неудач Patch2Vuln - здесь. Для пакетов, собранных с
-O2 -flto, покрытие diff систематически хуже, чем для -O0 или -Og.Behavioral validation остаётся нерешённой. Из 20 security-пар только 2 получили behavioral differential. Генерация PoC-ввода - фундаментально сложная задача: deep state bugs в парсерах, race conditions, kernel-специфичные пути - всё это за пределами текущих возможностей agent-подхода. Crash - самый простой сигнал, но далеко не все уязвимости приводят к crash. CWE-125 out-of-bounds read, как в CVE-2014-0160 Heartbleed, проявляется утечкой данных, а не падением процесса.
Контекстное окно конечно. Декомпилированный код сложных функций ядра может занимать тысячи строк. Pipeline вынужден обрезать контекст. Одна из 20 неудач - ошибка экспорта контекста: функция попала в кандидаты, но урезанный декомпилированный фрагмент лишил агента ключевой информации. Классическая ситуация: самое интересное оказалось за границей окна.
False positive rate не оценён при масштабе. Все 5 negative controls отвергнуты - отлично, но 5 образцов статистически ничего не доказывают. Реальный поток обновлений содержит десятки non-security пакетов на каждый security-фикс.
Kernel modules - за пределами бенчмарка. Patch2Vuln тестировался на userspace-бинарниках (tcpdump, libexpat, libarchive). Модули ядра с RCU-секциями, memory barriers, per-CPU структурами - совсем другой зверь. Use-after-free в io_uring или race condition в netfilter требует понимания контекста, который декомпилятор передаёт плохо: lifetime аллокаций, порядок блокировок, атомарность операций.
Стоимость масштабирования. Bishop Fox показали: authorization bypass с 1400+ функций стоит $35 за прогон на Claude Sonnet 3.7. Для массового триажа сотен .deb-пар бюджет набегает серьёзный. Локальные модели - потенциальная альтернатива, но их качество на security reasoning пока не бенчмаркировано в аналогичных условиях.
Patch2Vuln задаёт правильную рамку: это не «автоматическая генерация эксплойтов», а исследование глубины, на которую LLM-агент проникает в семантику security-патча при наличии только бинарных артефактов. 10 из 20 - половина, но с прозрачной диагностикой провалов, позволяющей целенаправленно улучшать bottleneck-компоненты.
Два года работы с LLM в контексте ELF binary analysis убедили меня в одном: модели хорошо справляются со structured reasoning по готовому контексту, но плохо - с extraction этого контекста из сырых бинарей. Patch2Vuln количественно подтверждает эту интуицию. Следующий рывок будет не в промптинге и не в более мощных моделях, а в дифферах и ранкерах. Если Ghidriff или его наследники начнут надёжно выделять security-relevant изменения в оптимизированных бинарниках с учётом compiler-induced noise (stack canaries, CFI instrumentation, register allocation changes), то 10/20 превращается в 16/20 без замены LLM-компонента. Формула на бумаге понятна, но реальное ощущение bottleneck появляется только когда сам прогоняешь pipeline на дюжине .deb-пар и видишь, как ранкер раз за разом кладёт security-функцию на 50-е место из 200 кандидатов. Готовый стенд для отработки подобных навыков - от бинарного артефакта до восстановленной логики уязвимости - есть на HackerLab.pro в категории reverse.
Для defensive teams вывод практический: patch intelligence - мониторинг upstream-коммитов с автоматической классификацией security-relevance - перестаёт быть nice-to-have и становится baseline control. Для offensive research вывод жёстче: n-day window сокращается для всех, и конкурентное преимущество теперь не в «знаю LLM» (его знают все), а в качестве binary-diff pipeline, speed validation loop и, как обычно, в глубине понимания target subsystem. Если хочешь работать с binary patch analysis на реальных ELF-артефактах - на HackerLab лежит сценарий, где бинарный primitive нужно собрать в полную цепочку.