Статья Эксплуатация CVE в пентесте: от публичного PoC до стабильного шелла в обход EDR

Серверный блейд, наполовину извлечённый из стойки, с янтарной надписью на LCD-панели. Тёплый свет настольной лампы падает на металл, рядом свёрнутый кабель уходит в тень.


Ты нашёл свежий CVE на периметре клиента. GitHub выдаёт три PoC: две - форки одного Python-скрипта, третий - на Go. Запускаешь первый против лабораторного стенда - сервис уходит в crash loop. Второй не отрабатывает check и молча завершается. Третий собирается, но рассчитан на другую минорную версию. Три PoC, ноль шеллов. Если ты занимался эксплуатацией CVE в пентесте хотя бы полгода - ты знаешь это чувство.

По данным Arctic Wolf, в 2024 году опубликовано 40 289 CVE - рост на 72% относительно 2023-го. Критических и высокоприоритетных стало больше на 13,46%. Среди них - цепочки в Ivanti Connect Secure, Palo Alto PAN-OS и ConnectWise ScreenConnect, которые эксплуатировались задолго до выхода патчей. Для Red Team оператора это непрерывный поток точек входа (T1190, Initial Access) - но только если умеешь превратить сырой PoC в рабочий инструмент, а не просто ронять сервис.

Здесь разбираю полный цикл weaponization: от оценки публичных PoC эксплойтов до интеграции в Metasploit и Sliver C2 фреймворк, стабилизации шелла и обхода EDR после первоначального доступа.

Почему три PoC из четырёх роняют процесс вместо шелла​

Публичные PoC эксплойты решают одну задачу - доказать, что уязвимость существует. Не дать стабильный шелл. Не обойти EDR. Не сохранить работоспособность сервиса. Между «уязвимость подтверждена» и «есть контролируемое выполнение кода» - часы, а иногда дни адаптации. И это нормально.

Возьмём CVE-2024-3400 - command injection в GlobalProtect компоненте PAN-OS. По NVD: CVSS 10.0 (CRITICAL), вектор AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H. CWE-20 (Improper Input Validation) и CWE-77 (Command Injection). Неаутентифицированный атакующий выполняет произвольный код с root-привилегиями на файрволле. Казалось бы - идеальный кандидат для первоначального доступа Red Team. Бери и заходи.

Но Unit 42 в расследовании Operation MidnightEclipse задокументировало четыре уровня реальной эксплуатации - и картина куда менее радужная:
  • Level 0 - проба: попытка не удалась, никакого воздействия на устройство
  • Level 1 - тест: создан файл нулевого размера, но команды не выполнены
  • Level 2 - потенциальная эксфильтрация: running_config.xml скопирован в web-доступную директорию
  • Level 3 - интерактивный доступ: полноценный шелл с бэкдором
Подавляющее большинство реальных попыток эксплуатации застряли на Level 0-1. Даже APT-группа за Operation MidnightEclipse трижды безуспешно пыталась установить Python-бэкдор UPSTYLE, прежде чем плюнула и переключилась на cron job. Это к вопросу о том, что даже таргетированная атака с кастомным тулингом - не гарантия стабильного результата. CVSS 10.0 на бумаге и CVSS 10.0 в бою - две разные истории.

Я сталкивался с похожей ситуацией на нескольких проектах: PoC с GitHub красиво отрабатывает на стенде с точной версией из advisory, а на боевом таргете - тишина или crash. Причины типичные, и стоит разобрать их по отдельности.

Типичные причины, по которым PoC не работает​

Жёсткая привязка к версии. Автор PoC проверил эксплойт на одном конкретном билде. Смещения в памяти, адреса гаджетов для ROP-цепочки, размеры структур - всё это плывёт между минорными версиями. PoC для PAN-OS 11.1.2-h1 может молча падать на 11.1.2-h3, потому что Palo Alto перекомпилировала один бинарник с другими флагами оптимизации.

Отсутствие стабилизации. Большинство публичных PoC эксплойтов - это proof of concept в буквальном смысле. Автор доказал возможность выполнения кода и на этом остановился. Никакого восстановления потока выполнения после перехвата управления, никакой очистки за собой. Сервис падает - а тебе ещё работать на этом периметре.

Среда выполнения. PoC написан под чистую систему без EDR, без сетевых фильтров, без WAF. На боевом таргете между тобой и уязвимым сервисом может стоять reverse proxy, который режет нестандартные заголовки, или EDR, который убивает cmd.exe при подозрительном parent process.

Неполная эксплуатация. Многие PoC демонстрируют только часть цепочки. Например, для CVE-2024-3400 ранние PoC показывали запись файла (Level 1-2), но не давали выполнение команд (Level 3). Между «записать файл» и «получить шелл» - ещё один этап работы, который автор PoC оставил читателю в качестве домашнего задания.

Оценка PoC: что проверять перед запуском​

Прежде чем тянуть PoC с GitHub и запускать его даже на стенде, стоит потратить 15-20 минут на оценку. У меня сложился простой чеклист, который экономит часы отладки.

Репутация источника​

Первое - кто автор. PoC от исследователя с историей публикаций (Project Zero, ZDI, или хотя бы профиль с другими рабочими эксплойтами) - это одно. Форк форка с двумя звёздами и коммитом «fix typo» - совсем другое. На одном проекте коллега запустил такой «PoC» и получил reverse shell к автору скрипта вместо таргета. Классика supply chain в мире эксплойтов.

Проверяй исходник глазами. Если PoC обфусцирован или тянет зависимости с левых URL - это не PoC, это малварь.

Соответствие версии​

Смотри, для какой точной версии написан эксплойт. Не «PAN-OS 11.x», а конкретный билд. Сравни с тем, что торчит на таргете. Если версии расходятся - готовься адаптировать. Иногда достаточно поменять offset, иногда нужно переписывать всю цепочку.

Тип уязвимости vs. тип PoC​

Command injection - одно. Memory corruption - другое. Для command injection PoC обычно переносится между версиями легче (если точка инъекции не изменилась). Для heap overflow или use-after-free - каждый билд может требовать пересчёта heap layout.

Что PoC реально делает​

Читай код, не только README. Многие PoC заявляют «RCE», а по факту делают touch /tmp/pwned. Между записью файла и выполнением произвольного кода - пропасть. Определи, на каком уровне (вспоминаем Level 0-3 от Unit 42) находится конкретный PoC, и сколько работы нужно, чтобы довести его до шелла.

Weaponization: от сырого PoC к стабильному эксплойту​

Допустим, PoC прошёл оценку и на стенде хотя бы частично отрабатывает. Дальше начинается собственно weaponization - превращение proof of concept в инструмент, которым можно пользоваться в бою.

Стабилизация эксплойта​

Первый шаг - сделать так, чтобы эксплойт не ронял сервис. Для memory corruption уязвимостей это означает восстановление потока выполнения после перехвата управления. Для command injection - использование техник, которые не оставляют процесс в не согласованном виде.

На практике это часто означает замену грубого system("bash -i >& /dev/tcp/...") на что-то более аккуратное. Например, запись шелл-кода в файл через уязвимость и его выполнение через легитимный механизм (cron, systemd timer, at job). Да, медленнее. Зато сервис продолжает работать, а у тебя есть стабильный callback.

Обход EDR на этапе первоначального доступа​

EDR на периметре - уже не редкость. CrowdStrike, SentinelOne, Defender for Endpoint - всё это может стоять на хосте за уязвимым сервисом. И если твой эксплойт порождает cmd.exe от имени httpd - алерт прилетит раньше, чем ты увидишь шелл.

Несколько приёмов, которые работают (на момент написания - EDR тоже не стоят на месте):

Вместо порождения нового процесса - инъекция в существующий. Если уязвимость даёт запись в память или выполнение кода в контексте процесса, используй это. Shellcode, который живёт в памяти уязвимого процесса и не порождает дочерних - сложнее для детекта.

Для command injection - избегай очевидных паттернов. bash -c, powershell -enc, certutil -urlcache - всё это давно в сигнатурах. Лучше использовать встроенные средства конкретного приложения. PAN-OS, например, содержит Python - и APT-группа за MidnightEclipse это использовала, написав бэкдор UPSTYLE именно на Python, интегрированном в PAN-OS.

Интеграция в C2 фреймворк​

Отдельный скрипт - это хорошо для проверки на стенде. Для реального проекта нужна интеграция в C2 фреймворк: Metasploit, Sliver, Cobalt Strike, Mythic.

Для Metasploit это означает написание модуля с правильным check методом (который верифицирует уязвимость без эксплуатации), поддержкой нескольких targets (версий), и интеграцией с payload framework. Да, это дополнительная работа. Но потом ты можешь использовать exploit/multi/handler, автоматический роутинг через pivots, и весь остальной арсенал MSF.

Для Sliver - генерация implant под целевую платформу и доставка через эксплойт. Sliver даёт больше гибкости с протоколами коммуникации (mTLS, WireGuard, DNS, HTTP/S), что помогает при обходе сетевых фильтров на периметре.

Я предпочитаю Sliver для внешних операций - меньше сигнатур по сравнению с Cobalt Strike, нативная поддержка кросс-компиляции, и бесплатный. Metasploit оставляю для этапа разработки и тестирования эксплойта, а финальную доставку делаю через Sliver.

Пример: адаптация PoC для CVE-2024-3400​

Вернёмся к PAN-OS. Публичные PoC для CVE-2024-3400 к моменту массовой эксплуатации делали следующее: отправляли crafted HTTP-запрос с path traversal в cookie SESSID, который создавал файл в произвольной директории. Это Level 1 по классификации Unit 42.
🔓 Эксклюзивный контент для зарегистрированных пользователей.
Между шагами 1 и 2 - задержка до минуты (зависит от конфигурации cron). Это нормально. Зато GlobalProtect продолжает работать, а ты получаешь стабильный канал.

Пост-эксплуатация: первые 60 секунд после шелла


1776808021202.webp


Шелл получен. Часы тикают. EDR может среагировать на аномальное поведение процесса, SOC может заметить алерт, а сервис может перезапуститься по watchdog. Первые 60 секунд критичны.

Ситуационная осведомлённость. Прежде чем делать что-либо - пойми, где ты. ОС, привилегии, сетевое окружение, наличие EDR. На Linux: id, uname -a, ps aux | grep -i edr, ls /opt/. На PAN-OS (или другом appliance) - набор команд будет специфичным для платформы.

Персистенс. Если шелл нестабилен (а после эксплуатации CVE он часто нестабилен), первое действие - закрепиться. Не через тот же вектор (уязвимость могут пропатчить), а через независимый механизм. SSH-ключ, cron job, модификация легитимного скрипта автозапуска. На appliance типа PAN-OS вариантов меньше, но они есть - тот же UPSTYLE из Operation MidnightEclipse закреплялся через модификацию logd.

Миграция. Если начальный шелл живёт в контексте уязвимого процесса - мигрируй в другой. Процесс может быть перезапущен, обновлён, или просто нестабилен после эксплуатации. Чем быстрее переедешь в стабильный процесс - тем меньше шансов потерять доступ.

Когда НЕ стоит эксплуатировать CVE​

Не каждый CVE на периметре стоит эксплуатировать. Звучит странно для статьи про weaponization, но это тот случай, когда «можно» не значит «нужно».

Если уязвимость в критичном production-сервисе без возможности быстрого восстановления - подумай дважды. Crash loop на VPN-концентраторе в пятницу вечером - это не тот результат, который клиент ожидает от Red Team. Даже если в scope записано «эксплуатация разрешена».

Если есть менее рискованный вектор (слабые пароли, SSRF через внутренний сервис, фишинг) - часто разумнее зайти через него, а CVE задокументировать как подтверждённую уязвимость без эксплуатации. В отчёте это выглядит так же, а риск для инфраструктуры клиента - ниже.

На одном проекте мы нашли RCE в Exchange (ProxyNotShell, CVE-2022-41082), но рядом торчал Confluence с дефолтными кредами admin:admin. Угадай, через что мы зашли. CVE в Exchange всё равно попал в отчёт как Critical, но ронять почту 500 сотрудникам ради красивого скриншота шелла - так себе идея.

Чеклист weaponization: от PoC до операции​

Для тех, кому нужна структура - вот последовательность, которой я придерживаюсь:
  1. Найти и оценить PoC: автор, версия, что реально делает, нет ли закладок
  2. Развернуть стенд с точной версией таргета (Docker, VM, cloud instance)
  3. Воспроизвести PoC на стенде, зафиксировать поведение
  4. Стабилизировать: убрать crash, восстановить поток выполнения
  5. Заменить payload: вместо calc.exe / touch /tmp/pwned - реальный implant
  6. Протестировать с EDR на стенде (хотя бы Defender)
  7. Интегрировать в C2 фреймворк
  8. Задокументировать: версии, offsets, ограничения, rollback-план
  9. Согласовать с заказчиком окно эксплуатации
  10. Выполнить, закрепиться, мигрировать, продолжить операцию
Шаги 2-6 можно уложить в день, если уязвимость command injection. Для memory corruption - закладывай два-три дня минимум. Для цепочки из нескольких CVE - неделю.

Что дальше​

Три PoC с GitHub и ноль шеллов - это не провал, это стартовая точка. Разница между оператором, который умеет только запускать чужие скрипты, и тем, кто стабильно получает доступ через свежие CVE - в этом цикле weaponization. Оценка, адаптация, стабилизация, интеграция в C2, обход EDR.

Возьми последний CVE из своего скоупа, который ты отложил со словами «PoC не работает». Разверни стенд, открой PoC в редакторе (не в терминале), и пройди по чеклисту выше. Скорее всего, до шелла - пара часов работы, а не «нерабочий эксплойт».

Вопрос к читателям​

Коллеги, кто адаптировал эксплуатацию CVE-2024-3400 до Level 3 на реальном таргете - как решали проблему задержки между записью payload в /etc/cron.d/ и его выполнением? Конкретно интересует: использовали ли вы at-джобы как альтернативу cron для сокращения окна ожидания, или шли через модификацию существующего скрипта в /etc/periodic/? И второй момент - при доставке implant через Sliver с mTLS на порту 443 через GlobalProtect: какой generate-флаг использовали для обхода TLS-инспекции на самом файрволле (--skip-symbols, кастомный C2 profile, или что-то ещё)? Поделитесь конкретной командой sliver-client generate или фрагментом Metasploit-модуля с targets-блоком под разные билды PAN-OS 11.x.
 
Последнее редактирование модератором:
Мы в соцсетях:

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

Похожие темы

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

HackerLab