Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
Инструменты/GitHubGitHub/squeeze440/crw-poc
Анализ уязвимостейЭксплуатацияВеб-безопасностьТестирование на Проникновение
GitHubsqueeze440/crw-poc

crw-PoC

PoC — SSRF через обход фильтра безопасности URL на уровне JS-рендеринга в crw (GHSA-5jp3-339h-vxqw, CVE-2026-87007, CVSS 7.5).

Репозиторий
7 дней назадЕщё не проверено

Популярное

Смотреть все →

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

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

crw: рекомендации по безопасности

Статус CVE: запрошен, ожидает присвоения. Данная уязвимость опубликована как GHSA-5jp3-339h-vxqw. После присвоения CVE этот репозиторий будет переименован в CVE-YYYY-NNNNN-crw-PoC, а данный баннер заменён ссылкой на CVE.

ИсследовательDostxodjayev Abdullox (@squeeze440)
РекомендацияGHSA-5jp3-339h-vxqw
CVSS 3.17.5 (High)
СлабостьCWE-918

Краткое описание

В crw-server список разрешённых/запрещённых адресов для защиты от SSRF (crw_core::url_safety) применяется только один раз — к переданному вызывающей стороной url — до того, как запрос направляется в рендерер; после этого уровни JS-рендеринга на основе CDP (LightPanda — JS-рендерер по умолчанию — и Chrome) управляют целевой страницей через Page.navigate и выполняют все последующие перенаправления, переходы, инициированные JS, и внутристраничные XHR/fetch полностью внутри собственного сетевого стека браузера, без каких-либо дальнейших обращений к url_safety, что позволяет аутентифицированному (или, при развёртывании по умолчанию без ключей, неаутентифицированному) вызывающему, установившему renderJs:true, перенаправить краулер в адресное пространство RFC1918/loopback/link-local через единственное внешнее открытое перенаправление и прочитать ответ внутреннего сервиса в теле ответа API.

Продукт

fastCRW / crw — crw-server (REST API, также доступный идентичным образом через внутрипроцессный слой MCP-инструментов crw-mcp, который вызывает тот же путь кода crw_server::routes::mcp::call_tool).

Протестированная версия

Коммит 9f1e5ea5555bbf29cd41e454902be0cd804a15e4 (v0.28.0, вершина main на момент тестирования), собран и запущен через собственный docker-compose.yml --profile heavy проекта.

Оценка CVSS v3.1

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N — 7.5 (High)

  • PR:N: поставляемая конфигурация self-host по умолчанию (config.docker.toml) не содержит секции [auth]/api_keys, что соответствует задокументированному значению по умолчанию «открыто по замыслу» в GHSA-qq8c-fch4-cxq7. Развёртывание, которое действительно настраивает API-ключи, понижает это до PR:L (любой отдельный аутентифицированный арендатор всё ещё может перенаправить общий движок в любую внутреннюю сеть, в которой он работает) — уязвимость не устраняется добавлением ключей, а лишь повторно ограничивается.
  • I:N/A:N: PoC демонстрирует чтение ответа внутреннего HTTP-сервиса (конфиденциальность). Никаких действий по записи/изменению состояния против внутренней цели не выполнялось и не заявляется.
  • S:U: раскрытие опосредовано исключительно через собственный канал ответа API уязвимого компонента.

Детали

Первопричина: путь CDP/браузерного рендерера никогда не вызывает crw_core::url_safety после единственной проверки, выполненной на уровне маршрута.

  • crates/crw-server/src/routes/scrape.rs:29-34 (идентично в crawl.rs:47/136, map.rs:73/58, extract.rs:178/95, batch.rs:111/102, v2/*, routes/mcp.rs:25) — единственная проверка SSRF за весь жизненный цикл запроса для JS-рендерируемого запроса: crw_core::url_safety::validate_safe_url_resolved(&parsed_url) выполняется один раз для буквального url вызывающей стороны, до того как рендерер вообще будет вызван.
  • crates/crw-renderer/src/cdp.rs:2621-2631 — future work в fetch_inner отправляет Page.navigate с необработанным url напрямую в конечную точку CDP (общую как для уровня chrome, так и для lightpanda — оба общаются по CDP через эту же функцию). Затем Chrome/LightPanda выполняет собственное разрешение DNS и следует любому серверному перенаправлению, <meta http-equiv="refresh"> или изменению location в JS внутри себя. Нигде в cdp.rs нет вызова url_safety.
  • crates/crw-renderer/src/blocklist.rs:1-124 — единственная логика перехвата Fetch.requestPaused для каждого запроса, которая выполняется во время CDP-рендеринга (подключена в cdp.rs примерно в строках 930-1002). Она фильтрует хосты рекламы/трекеров и заблокированные типы ресурсов (изображения, шрифты и т. д.) исключительно по причинам пропускной способности/шума — она никогда не проверяет назначение запроса на принадлежность к приватным/loopback/link-local диапазонам.
  • crates/crw-crawl/src/single.rs:559-569 — единственное место, где вообще проверяется final_url после навигации. redirect_is_material() лишь решает, прикреплять ли косметическую строку "redirected_to: <url>" к data.warnings (чтобы отметить «вы получили не ту страницу», согласно комментарию, ссылающемуся на northernair.ca) — она никогда не вызывает url_safety::validate_safe_url* и никогда не завершает запрос с ошибкой.
  • Для сравнения: crates/crw-renderer/src/http_only.rs:291 — уровень обычного HTTP (без JS) корректно оборачивает свой reqwest::Client в crw_core::url_safety::safe_redirect_policy(), который повторно проверяет (с разрешением DNS) каждый шаг перенаправления. Именно этой защиты не хватает уровням CDP. Динамически подтверждено: тот же PoC-запрос с renderJs:false корректно отклоняется ("error following redirect", см. скриншот базовой линии).

Доказательство концепции

Динамически подтверждено на собственном стеке docker-compose.yml --profile heavy проекта (crw + lightpanda + chrome, собранном из протестированного коммита).

  1. Развёрнут заменитель «внутреннего сервиса» в той же сети Docker bridge, что и crw/chrome/lightpanda (docker network: source_default), по приватному адресу 172.19.0.6 — обычный контейнер nginx, отдающий страницу с реалистичным внутренним содержимым (заголовок «Internal Ops Console», значение в форме токена сессии).
  2. Базовая линия — подтверждение, что фильтр работает нормально:
    root@kitploit:~
    curl -s -X POST http://127.0.0.1:3000/v1/scrape -H "Content-Type: application/json" \
      -d '{"url":"http://172.19.0.6/","renderJs":false}'
    → {"success":false,"error":"Invalid request: Access to 172.19.0.6 is not allowed", ...}
    
    curl -s -X POST http://127.0.0.1:3000/v1/scrape -H "Content-Type: application/json" \
      -d '{"url":"https://httpbin.org/redirect-to?url=http://172.19.0.6/&status_code=302","renderJs":false}'
    → {"success":false,"error":"HTTP request failed: error following redirect ...", ...}
    
    (скриншот: evidence/ssrf_baseline_blocked.png)
  3. Обход — то же перенаправление, запрошен уровень JS-рендеринга:
    root@kitploit:~
    curl -s -X POST http://127.0.0.1:3000/v1/scrape -H "Content-Type: application/json" \
      -d '{"url":"https://httpbin.org/redirect-to?url=http://172.19.0.6/&status_code=302","renderJs":true,"renderer":"chrome","formats":["markdown"]}'
    
    Результат: HTTP 200, "success":true, "data":{"markdown":"# Internal Ops Console\n\n# internal-ops.crw-lab.local\n\nNode role: primary\n\nBuild: 2026.08.02-rc3\n\nSession token: 8f3d1c9a7e2b4460b9e5d6a1c0f7e3d2", ..., "warnings":["redirected_to: http://172.19.0.6/"], "renderDecision":{"kind":"userPinned","renderer":"chrome"}} — содержимое внутреннего сервера возвращается вызывающей стороне; собственное предупреждение redirected_to инструмента показывает, что он знает, что последовал запросу к заблокированному адресу, и всё равно возвращает содержимое. (скриншот: evidence/ssrf_chrome_tier_bypass.png)
  4. Подтверждено, что обход также срабатывает на цепочке по умолчанию без явного закрепления рендерера (только "renderJs":true — обычный способ, которым вызывающая сторона запрашивает JS-рендеринг): лестница выбрала lightpanda ("renderDecision":{"kind":"autoDefault","chosen":"lightpanda"}, "renderedWith":"lightpanda") и вернула то же внутреннее содержимое, доказывая, что оба уровня CDP (не только chrome) имеют этот пробел.

https://httpbin.org/redirect-to выступает в роли «любого внешне доступного URL, отвечающего 302»; реальный злоумышленник разместил бы это на своём домене. 172.19.0.6 выступает в роли любого адреса из диапазонов, которые url_safety предназначен блокировать (RFC1918, loopback, link-local/169.254.169.254 облачные метаданные, .internal) — обход происходит до того, как выполняется любая проверка диапазона (путь CDP вообще никогда не вызывает url_safety), поэтому он не специфичен для этого одного заблокированного диапазона. Живая конечная точка облачных метаданных была недоступна в этой локальной лаборатории, поэтому эта конкретная цель не была напрямую задействована; это прямое, отслеженное по коду экстраполирование, а не непроверенное утверждение.

Воздействие

Любой вызывающий, способный достичь /v1/scrape, /v2/scrape, /v1/crawl, /v1/map, /v1/extract, их batch/v2-эквивалентов или эквивалентных MCP-инструментов — с renderJs:true — может использовать целевое развёртывание crw как открытый прокси во внутреннюю сеть: читать ответы от loopback-сервисов развёртывающего, внутренних сервисов с адресами RFC1918 (базы данных, панели администрирования, внутренние API) и — при любом облачном развёртывании — конечной точки облачных метаданных экземпляра (169.254.169.254), потенциально извлекая учётные данные IAM/экземпляра. При поставляемой конфигурации self-host по умолчанию (API-ключи не настроены) это вообще не требует аутентификации.

Слабости

  • CWE-918: Server-Side Request Forgery (SSRF)
  • CWE-441: Unintended Proxy or Intermediary ('Confused Deputy')

Устранение

Насос перехвата Fetch.requestPaused, уже подключённый к уровням CDP (crates/crw-renderer/src/cdp.rs, управляемый Blocklist в blocklist.rs), является естественной точкой контроля: расширьте его (или добавьте родственную проверку, вызываемую из того же насоса, для обоих бэкендов chrome и lightpanda), чтобы вызывать crw_core::url_safety::validate_safe_url для URL каждого перехваченного запроса — охватывая начальную навигацию, каждый шаг перенаправления, каждую навигацию, управляемую JS, и каждую загрузку XHR/fetch/iframe на той же странице — и Fetch.failRequest для всего, что разрешается в заблокированный хост, соответствуя тому, что safe_redirect_policy() уже делает для уровня http_only. Обратите внимание, что это означает, что Fetch.enable/перехват больше не может оставаться условно отключённым, когда защита от SSRF зависит от его работы. В качестве эшелонированной защиты также превратите существующую проверку final_url после навигации в crates/crw-crawl/src/single.rs:559-569 из косметической записи в warnings в жёсткий сбой через url_safety::validate_safe_url_resolved, чтобы перехватывать всё, что проскользнёт мимо перехвата (например, самый первый ответ, опережающий настройку Fetch.enable).

Благодарность

Dostxodjayev Abdullox

Канал сообщения об уязвимостях

.github/SECURITY.md (отображается на https://github.com/us/crw/security): GitHub Private Vulnerability Reporting является предпочтительным каналом («откройте отчёт со вкладки Security этого репозитория»), с [email protected] в качестве резервного адреса электронной почты. Подтверждено, что он действительно активен и открыт для этого репозитория: gh api repos/us/crw/private-vulnerability-reporting --jq .enabled → true, и на https://github.com/us/crw/security наблюдалась активная кнопка «Report a vulnerability» (ведущая на https://github.com/us/crw/security/advisories/new). Заявление об области действия на этой странице явно включает «Бинарный файл crw-server и все крейты рабочего пространства в этом репозитории» и «MCP-сервер (crw-mcp)»; оно исключает «Сторонние headless-браузеры (Chromium, Lightpanda), вызываемые рендерером» — данная находка касается отсутствующей валидации в самом crw вокруг вызова навигации CDP, а не ошибки в самом Chromium/Lightpanda, поэтому она входит в область действия.

Скачать инструмент