РАЗБОР
На проверке
Определение сервера, приложения и фреймворка
[ обложка статьи ]
Режим чтения
Заголовок
Server: Website.com в HTTP-ответе - реальный пример из OWASP Web Security Testing Guide. За изменённым баннером скрывается конкретный веб-сервер, но порядок остальных полей в ответе совпадает с поведением Nginx, а не Apache. Один признак - гипотеза. Два - направление. Три из разных слоёв стека - основание для записи в отчёт. Здесь разберём процедуры определения технологического стека (fingerprinting): от веб-сервера до фреймворка и приложения по методологии WSTG-INFO-02, WSTG-INFO-08 и объединённой WSTG-INFO-09.Паспорт наблюдения
Прежде чем запускать инструменты, стоит определиться с форматом записи. Каждый обнаруженный признак фиксируется в виде паспорта наблюдения - структуры, которая связывает конкретный артефакт с архитектурным слоем и уровнем уверенности:- URL или хост - адрес, по которому получен ответ.
- Слой архитектуры - к чему относится признак: CDN / балансировщик, reverse proxy, веб-сервер, application server, фреймворк, CMS.
- Признак - конкретное наблюдение: значение заголовка, имя cookie, путь к файлу, HTML-комментарий.
- Предполагаемый продукт - название ПО, на которое указывает признак.
- Версия - точная версия, если она явно раскрыта; «не установлена», если признак указывает на продукт без номера версии.
- Степень уверенности - высокая (несколько независимых признаков из разных слоёв), средняя (один-два признака без противоречий), низкая (единственный признак, который может быть подделан).
Определение веб-сервера (WSTG-INFO-02)
Задача - установить тип и определение версии сервера, на котором работает целевое приложение. Серверы с устаревшим ПО без актуальных патчей безопасности могут быть подвержены эксплойтам, специфичным для конкретных версий.Цель тестирования по WSTG: определить версию и тип работающего веб-сервера для дальнейшего поиска известных уязвимостей.
Методы: сбор серверных баннеров (banner grabbing), провоцирование ответов на некорректные запросы и применение автоматических средств. Общий принцип один - вызвать у сервера ответ, который можно сопоставить с базой известных ответов и поведений, и соотнести с известным типом сервера.
Сбор серверных баннеров
Сбор серверных баннеров (banner grabbing) - отправка HTTP-запроса и анализ заголовков ответа. Для этого подходятcurl -I (шлёт HEAD-запрос и показывает только заголовки), httpx для массовой проверки больших списков хостов или openssl s_client для запросов через TLS/SSL.
Код:
curl -I https://example.org
Server явно раскрывает тип и версию - Server: Apache/2.4.43 (Unix). Порядок заголовков характерен: Date, Server, Last-Modified, ETag, Accept-Ranges, Content-Length, Connection, Content-Type.Для Nginx порядок иной:
Server, Date, Content-Type, далее Content-Length, Last-Modified.Для lighttpd - ещё один вариант:
Content-Type идёт первым, далее Accept-Ranges, ETag, Last-Modified, Content-Length, Connection, Date, а Server - последним.Но приложения, заботящиеся о безопасности, могут модифицировать заголовок
Server. WSTG приводит ответ с Server: Website.com. Тут тестировщик может предположить тип сервера по порядку оставшихся полей: если последовательность совпадает с Nginx (Server, Date, Content-Type), это косвенно указывает на Nginx. Метод не даёт однозначного результата - разные серверы могут использовать одинаковый порядок, а поля могут быть изменены или удалены.Отправка некорректных запросов
Веб-серверы можно идентифицировать по их ответам на ошибки - особенно если страницы ошибок не кастомизированы. Один из способов: отправка намеренно некорректного запроса с несуществующей версией HTTP-протокола.WSTG демонстрирует запрос
GET / SANTA CLAUS/1.1. Ответы принципиально различаются:- Apache возвращает
HTTP/1.1 400 Bad Requestс HTML в формате<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">и текстом «Your browser sent a request that this server could not understand». - Nginx возвращает
404 Not Found(другой код ошибки на тот же запрос!) с характерным HTML - теги<center>и<hr>, версия в<center>nginx/1.17.3</center>. - lighttpd возвращает
HTTP/1.0 400 Bad Requestс XML-декларацией и XHTML Transitional DOCTYPE.
Server эти различия позволяют определить тип сервера. Для идентификации по стандартным страницам, не раскрывающим тип напрямую, WSTG ссылается на каталог стандартных ошибок.Автоматические средства сканирования веб-технологий
Автоматические сканеры выполняют запросы, аналогичные описанным выше, плюс шлют серверо-специфичные пробы. Они сопоставляют ответы с базами известных реакций значительно быстрее ручного тестирования - потому чаще дают точный результат.WSTG перечисляет инструменты с функцией фингерпринтинга:
- Netcraft Site Report - онлайн-сервис, собирающий информацию о сайтах, включая данные о веб-сервере.
- Nikto - open-source сканер командной строки.
- Nmap - open-source инструмент командной строки с GUI Zenmap; nmap service detection определяет версии сервисов.
- WhatWeb и
httpx(ключ-tech-detect) - определяют ПО веб-сервера наряду с другими технологиями стека.
Учебный сценарий: reverse proxy и слои стека
Контекст стенда. Локальный reverse proxy (Nginx) установлен перед приложением. ЗаголовокServer возвращает одно значение, X-Powered-By - другое.Действия. Отправить обычный
HEAD-запрос и зафиксировать заголовки. Изучить cookie в Set-Cookie. Запросить несуществующий путь и проанализировать страницу ошибки. Записать, какой слой даёт каждый признак.Условный результат. Заголовок
Server: nginx/1.24.0 - слой proxy (уверенность высокая: баннер и порядок заголовков совпадают). Заголовок X-Powered-By: PHP/8.2 - слой application server за proxy (уверенность средняя: заголовок может быть подменён). Cookie laravel_session - слой фреймворка (уверенность средняя: cookie может быть переименован). Вывод разделяет proxy и фреймворк; конкретная версия Laravel не установлена при отсутствии подтверждения.Ложный маркер. Администратор заменил заголовок
Server на произвольную строку через proxy_set_header. Поддельный Server-заголовок не меняет реально установленный компонент - если порядок остальных заголовков, страницы ошибок и реакция на некорректные запросы по-прежнему соответствуют Nginx, единичное изменение баннера не опровергает другие наблюдения.Идентификация фреймворка веб-приложения (WSTG-INFO-08)
Подавляющее большинство веб-приложений частично или полностью построены на известных фреймворках и CMS (WordPress, phpBB, MediaWiki и др.). Знание компонентов серьёзно помогает при тестировании и сокращает объём работы. Эти приложения обладают характерными HTML-заголовками, cookie и структурами каталогов. Большинство фреймворков оставляют несколько маркеров в типичных местах - именно так работают автоматические инструменты: ищут маркер в заранее определённом месте и сравнивают его с базой известных сигнатур (signature). Для повышения точности обычно используется несколько маркеров одновременно.Цель тестирования по WSTG: определить компоненты, используемые веб-приложением.
При тестировании методом чёрного ящика (Black-Box Testing) WSTG выделяет шесть категорий мест для поиска: HTTP-заголовки, cookie, HTML-код, специфичные файлы и каталоги, расширения файлов, сообщения об ошибках.
Заголовки и cookie как признаки фреймворка
HTTP-заголовки. Самый базовый способ - значениеX-Powered-By в HTTP-ответе. Пример: X-Powered-By: Mono указывает на .NET-совместимую среду. Заголовок легко отключить или подменить - WSTG приводит значение X-Powered-By: Blood, sweat and tears (и правда - пот и слёзы, если кто-то на это купится).Иногда заголовков несколько. Пример:
X-Powered-By: PHP/5.4.16-1~dotdeb.1 сообщает версию PHP, а X-Generator: Swiftlet дополнительно указывает на конкретный фреймворк. При сборе информации о веб-приложении нужно проверять все HTTP-заголовки на подобные утечки - анализ HTTP-заголовков не ограничивается одним полем.Cookies. Более надёжный способ - специфичные для фреймворка cookie. Laravel автоматически устанавливает
laravel_session и XSRF-TOKEN. Имена cookie можно переименовать (для Laravel - через cookie в config/session.php), но такие изменения вносятся реже, чем скрытие X-Powered-By. Cookie - более надёжный признак для определения CMS сайта, чем заголовки, именно потому что их реже трогают.HTML-код, маркеры, каталоги и расширения
HTML-код. Техника основана на поиске паттернов в исходном коде страницы. Распространённые маркеры: HTML-комментарии, ссылки на CSS/JS-папки фреймворка, переменные скриптов. Angular добавляет атрибутng-version к корневому элементу. Информация часто сидит в <head>, в <meta>-тегах или в конце страницы - но анализировать следует весь ответ. Иногда раскрытие оказывается в футере - «Proudly published with Ghost» указывает на платформу Ghost.Общие маркеры (General Markers). В HTML можно искать паттерны:
%framework_name%, powered by, built upon, running.Специфичные маркеры (Specific Markers):
| Фреймворк | Маркер |
|---|---|
| Adobe ColdFusion | <!-- START headerTags.cfm |
| Microsoft ASP.NET | __VIEWSTATE |
| ZK | <!-- ZK ...-->, скрипты в zkau/ |
| Indexhibit | ndxz-studio в <link> / <a href> |
| Next.js | <script id="[B]NEXT_DATA[/B]">, заголовок x-powered-by: Next.js |
| Nuxt | <div id="[B]nuxt", window.[/B]NUXT__, пути /_nuxt/ |
| htmx | JS-объект htmx, скрипт htmx.org@... |
Специфичные файлы и каталоги. Каждый компонент имеет характерную файловую структуру. Для её обнаружения применяется принудительный просмотр (dirbusting) - перебор известных путей с мониторингом HTTP-ответов. Для WordPress характерны
/wp-includes/, /wp-admin/, /wp-content/. Ответы 403, 302 (редирект на wp-login.php) и 200 соответственно - надёжный индикатор. Файл readme.txt плагина по пути /wp-content/plugins/<plugin-name>/readme.txt раскрывает версию через поле Stable tag.Совет из WSTG: перед dirbusting'ом проверить
robots.txt - строка Disallow: /wp-admin/ прямо указывает на WordPress. Для словарей пригодны FuzzDB wordlists of predictable files/folders. Если компонент имеет открытый код, полезно развернуть его временную копию - посмотреть структуру и понять, какие файлы могут остаться на сервере.Расширения файлов. URL-адреса могут содержать расширения:
.php - PHP, .aspx - Microsoft ASP.NET, .jsp - Java Server Pages.Сообщения об ошибках. Ошибки приложения раскрывают стек. Пример из WSTG: ошибка парсинга PHP в WordPress содержит путь
wp-content и имя functions.php - указывает и на CMS, и на язык одновременно.Таблицы распространённых идентификаторов
Идентификация по cookie:| Фреймворк | Имя cookie |
|---|---|
| WordPress | wordpress_logged_in_[I], wp-settings-[/I] |
| Laravel | laravel_session |
| Django | sessionid, csrftoken (по таблице WSTG-INFO-08) |
| Express.js (Node) | connect.sid |
| ASP.NET Core | .AspNetCore.Session, .AspNetCore.Antiforgery.* |
| phpBB | phpbb3_* |
| Drupal | SESS[I] / SSESS[/I] (имя - хеш) |
| CakePHP | CAKEPHP (настраиваемо) |
| TYPO3 | fe_typo_user |
| DNN Platform | DotNetNukeAnonymous |
Примечание: сигнатуры Django (
sessionid, csrftoken) указаны в таблице Common Identifiers WSTG-INFO-08. Имена sessionid и csrftoken - задокументированные дефолтные значения параметров SESSION_COOKIE_NAME и CSRF_COOKIE_NAME в Django Settings Reference. Deployment Checklist описывает лишь флаги CSRF_COOKIE_SECURE и SESSION_COOKIE_SECURE, относящиеся к защите этих cookie по HTTPS, а не сами имена.Идентификация по HTML-коду:
| Приложение | Маркер |
|---|---|
| WordPress | <meta name="generator" content="WordPress X.X" /> |
| phpBB | <body id="phpbb" |
| MediaWiki | <meta name="generator" content="MediaWiki X.X" /> |
| Joomla | <meta name="generator" content="Joomla! - Open Source Content Management" /> |
| Drupal | <meta name="Generator" content="Drupal X (https://drupal.org)" /> |
| Ghost | <meta name="generator" content="Ghost X.X" /> |
| DotNetNuke | DNN Platform - https://www.dnnsoftware.com |
| Angular | ng-version="X.X.X" на корневом элементе |
| Next.js | <script id="[B]NEXT_DATA[/B]" type="application/json"> |
Автоматическое распознавание: WhatWeb и аналоги
WhatWeb - один из наиболее известных open-source инструментов для определения технологий сайта. Входит в стандартную сборку Kali Linux, написан на Ruby. Текущая стабильная версия - 0.6.4, выпущенная 3 апреля 2026 года (по данным официального репозитория urbanadventurer/WhatWeb).Механизм WhatWeb основан на сигнатурах - каждая проверка использует один или несколько способов сопоставления:
- Текстовые строки (с учётом регистра)
- Регулярные выражения
- Запросы из Google Hack Database (ограниченный набор)
- MD5-хеши
- Распознавание URL-паттернов
- Паттерны HTML-тегов
- Пользовательский Ruby-код для пассивных и активных операций (пассивный и активный фингерпринтинг)
--plugins для выбора плагинов, --aggression для уровня интенсивности и различные форматы логирования.WSTG в разделе Tools к проверке INFO-08 указывает на существование множества специализированных утилит помимо универсальных, включая инструменты, ориентированные на конкретные фреймворки. Раздел References и Whitepapers ссылается на работы Saumil Shah «An Introduction to HTTP fingerprinting» и Anant Shrivastava «Web Application Finger Printing».
Учебный сценарий: статические пути и HTML-маркер
Контекст стенда. Учебное приложение развёрнуто на разрешённом стенде. В HTML-коде главной страницы присутствует тег<meta name="generator">, в структуре каталогов - характерные статические пути.Действия. Проверить HTML-код на наличие маркера в
<meta name="generator"> - допустим, обнаружен паттерн, совпадающий с шаблоном конкретной CMS. Через dirbusting проверить наличие специфичных каталогов этой CMS. Сопоставить две сигнатуры. Если стенд разрешает - обратиться к документированному version endpoint'у (например, readme.html или аналог).Условный результат. Продукт подтверждён двумя независимыми признаками: HTML-маркер (слой - HTML-код, уверенность средняя) и структура каталогов (слой - файловая система, уверенность средняя). Вместе они дают высокую уверенность в идентификации продукта. Версия указана в отчёте только при достаточном свидетельстве - например, если version endpoint явно раскрывает номер.
Ложный маркер. На стенде размещён
favicon.ico, скопированный с другого продукта. Скопированный favicon не доказывает использование этого продукта - для определения CMS требуется сопоставление нескольких независимых признаков. Вывод по одному файлу без подтверждения другими наблюдениями имеет низкую степень уверенности.Статус WSTG-INFO-09: определение приложения
Проверка WSTG-INFO-09 «Fingerprint Web Application» в текущей версии WSTG объединена с WSTG-INFO-08 «Fingerprint Web Application Framework». На официальной странице (WSTG-INFO-09) содержится только уведомление: «This content has been merged into: Fingerprint Web Application Framework».Определение конкретного приложения (WordPress, phpBB, MediaWiki) рассматривается как часть общей процедуры идентификации фреймворка из WSTG-INFO-08. Отдельная методология для INFO-09 не существует в текущем снапшоте - все описанные техники (заголовки, cookie, HTML-маркеры, каталоги, расширения, ошибки) покрывают задачу определения и фреймворка, и приложения одновременно.
От отпечатка к следующей гипотезе
Собранные отпечатки - отправная точка, не конечный результат. Типичная последовательность:- Проверить инвентарь. Сопоставить определённые компоненты с известным ПО организации (если инвентарь доступен). Это позволяет отличить ожидаемый стек от неавторизованных или забытых компонентов.
- Сопоставить версию с бюллетенями. Если версия определена - проверить наличие известных уязвимостей в бюллетенях вендора.
- Учитывать backport-патчи. Тут кроется ловушка, на которой горят многие. Как отмечает Red Hat в документации по бэкпортированию, номер версии пакета сам по себе не говорит, уязвим ли он. Вендор может держать старую upstream-версию (например, PHP 5.3), но с применёнными патчами безопасности. Red Hat приводит пример: исправление CVE-2014-3670 для PHP 5.3 в RHEL 6 было выполнено бэкпортом без обновления до upstream PHP 5.4. Инструменты, ориентирующиеся только на номер версии, дают ложные срабатывания.
- Выбрать релевантный тест. На основании определённого стека выбрать дальнейшие проверки, специфичные для конкретной CMS, фреймворка или версии сервера.
- Принимать ответ CDN за версию backend. Заголовок
Serverот CDN не отражает реально установленный исходный сервер приложения (origin server). Различать слои архитектуры - обязательное условие корректного вывода. - Сообщать о CVE по непроверенной версии или одному маркеру. Определение версии по единственному признаку - гипотеза, не факт. Заявлять о подверженности конкретной CVE допустимо при достаточном свидетельстве версии и проверке наличия backport-патчей.
Исправления и рекомендации
Для веб-сервера (по WSTG-INFO-02). WSTG рекомендует: скрытие информации в заголовках (например, модульmod_headers для Apache); использование защищённого reverse proxy как дополнительного слоя; поддержание актуальности ПО и установка патчей. Раскрытие информации о сервере само по себе не уязвимость - это информация, помогающая атакующему эксплуатировать другие уязвимости.Для фреймворка и приложения (по WSTG-INFO-08). Меры вроде изменения имён cookie, скрытия каталогов через URL rewriting, удаления заголовков - всё это, по формулировке WSTG, сводится к «security through obscurity». Такие меры замедляют самых начинающих атакующих, а время лучше потратить на поддержание решений в актуальном состоянии.
На практике:
- Обновлять подтверждённые компоненты и сверять патчи - с учётом различия upstream-версии и backport-патчей.
- Убирать ненужные диагностические баннеры и заголовки (
X-Powered-By,X-Generator, развёрнутые сообщения об ошибках). - Настраивать единые безопасные страницы ошибок, не раскрывающие путь к файлам или версию ПО.
- Не рассчитывать на то, что скрытие баннера само по себе защитит от чего-либо.
- WSTG-INFO-02 - Fingerprint Web Server (снимок от 2026-11-02)
- WSTG-INFO-08 - Fingerprint Web Application Framework (снимок от 2026-11-02)
- WSTG-INFO-09 - Fingerprint Web Application (объединена с INFO-08, снимок от 2026-11-02)
Русский перевод и редакционная актуализация - Codeby. Изменения относительно оригинала: объединение проверок INFO-02, INFO-08 и INFO-09 в единую статью; добавлены учебные сценарии с ложными маркерами и паспортом наблюдения; добавлен раздел о backport-патчах и типичных ошибках интерпретации версий; структура реорганизована по слоям стека; уточнён статус cookie-сигнатур Django. Лицензия перевода и адаптации: CC BY-SA 4.0.
Большинство отчётов, которые всплывают на профильных площадках, содержат один и тот же паттерн: «обнаружен Apache 2.4.49 - значит CVE-2021-41773 (активно эксплуатируется, включена в CISA KEV; использовалась в ransomware-кампаниях) - значит Critical». Фингерпринт подаётся как доказанная эксплуатация. Баннер показал версию - уязвим. Один cookie - фреймворк подтверждён. Заголовок от CDN - это backend.
В реальности номер версии в баннере не учитывает backport-патчи вендора. Один cookie может быть переименован или скопирован. Заголовок
Server от reverse proxy или CDN не имеет отношения к тому, что работает за ними. Определение технологического стека - не этап эксплуатации, а этап сбора гипотез, каждая из которых требует подтверждения независимыми признаками из разных слоёв. Два наблюдения - направление. Три из разных слоёв - основание для записи с указанием степени уверенности.Те, кто продолжает ставить Critical на основании одного баннера без проверки backport-патчей, обесценивают отчёт целиком. Это не вопрос инструментов - WhatWeb или Nmap одинаково честно покажут то, что видят. Вопрос в том, хватит ли дисциплины не записывать гипотезу как факт.
Вся серия WSTG · Предыдущая статья
Содержание
Codeby Academy
Практика и мастерство
От основ до продвинутого — программы для практиков Codeby.
Перейти к курсу →
Продолжить чтение
Следующий разбор
HTB writeup: цепочка XSS -> SSTI -> RCE пошагово
Комментарии
0