
Распознавание образов для хостов, сервисов и контента
# Recog: A Recognition Framework
[](https://github.com/rapid7/recog/actions/workflows/ci.yml)
[](https://github.com/rapid7/recog/actions/workflows/verify.yml)
Recog — это фреймворк для идентификации продуктов, сервисов, операционных систем и оборудования путём сопоставления отпечатков (fingerprint) с данными, полученными от различных сетевых зондов. Recog упрощает извлечение полезной информации из баннеров веб-серверов, полей описания системы SNMP и многого другого.
Recog является открытым программным обеспечением; дополнительную информацию см. в файле [LICENSE](https://github.com/rapid7/recog/blob/main/LICENSE).
## Table of Contents
1. [Repository split](#repository-split)
1. [Default branch rename](#default-branch-rename)
1. [Recog library language implementations](#recog-library-language-implementations)
1. [Feature parity](#feature-parity)
1. [Installation](#installation)
1. [Maturity](#maturity)
1. [Fingerprints](#fingerprints)
1. [Testing matches](#testing-matches)
1. [ftp_banners](#ftp_banners)
1. [http_cookies](#http_cookies)
1. [http_servers](#http_servers)
1. [favicons](#favicons)
1. [http_wwwauth](#http_wwwauth)
1. [tls_jarm](#tls_jarm)
1. [Contributing](#contributing)
## Repository split
31 марта 2022 года содержимое Recog — XML-файлы отпечатков и утилиты — было отделено от реализации библиотеки фреймворка Recog. Исходный репозиторий [Recog](https://github.com/rapid7/recog) теперь содержит содержимое Recog, а репозиторий [Recog-Ruby](https://github.com/rapid7/recog-ruby) содержит реализацию на языке Ruby. Содержимое Recog включено в Recog-Ruby как git-подмодуль и находится в каталоге `recog`. Все версии гема Recog после разделения, равные или больше 3.0.0, будут: 1) содержать каталог XML-отпечатков внутри каталога `recog` и 2) включать только инструмент `recog_match`, поскольку остальные инструменты ориентированы на управление отпечатками.
[^back to top](#recog-a-recognition-framework)
### Default branch rename
Вместе с разделением репозитория ветка по умолчанию была переименована с `master` на `main`. Все клоны, созданные до этих изменений, должны быть вручную обновлены в локальной среде. Если у вас есть форк, перейдите в его настройки и следуйте инструкциям по [переименованию ветки](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-branches-in-your-repository/renaming-a-branch), чтобы изменить ветку по умолчанию на `main`.
```
git branch -m master main
git fetch origin
git branch -u origin/main main
git remote set-head origin -a
```
При желании выполните следующую команду, чтобы удалить отслеживающие ссылки на старое имя ветки.
```
# сухой прогон для подтверждения устаревших ссылок, которые будут удалены перед выполнением
git remote prune origin --dry-run
git remote prune origin
```
Если вы ранее использовали вышестоящую отслеживающую ветку `upstream-master`, выполните следующие команды, чтобы удалить старую ветку и создать новую вышестоящую отслеживающую ветку.
```
git branch -d upstream-master
git checkout -b upstream-main --track upstream/main
```
При желании выполните следующую команду, чтобы удалить отслеживающие ссылки на старое имя вышестоящей ветки.
```
# сухой прогон для подтверждения устаревших ссылок, которые будут удалены перед выполнением
git remote prune upstream --dry-run
git remote prune upstream
```
[^back to top](#recog-a-recognition-framework)
## Recog library language implementations
* Ruby: [rapid7/recog-ruby](https://github.com/rapid7/recog-ruby)
* Java: [rapid7/recog-java](https://github.com/rapid7/recog-java)
* Go: [runZeroInc/recog-go](https://github.com/runZeroInc/recog-go)
[^back to top](#recog-a-recognition-framework)
### Feature parity
| Feature :sparkles: | rapid7/recog-ruby | rapid7/recog-java | runZeroInc/recog-go |
|---------------------------------------------|:------------------:|:------------------:|:-------------------:|
| Fingerprint verification CLI tool | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Fingerprint match CLI tool | :white_check_mark: | | :white_check_mark: |
| Supports base64 encoded examples | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Supports filesystem-based external examples | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Fingerprint match CPE param interpolation | :white_check_mark: | :white_check_mark: | :white_check_mark: |
[^back to top](#recog-a-recognition-framework)
## Installation
Recog состоит как из XML-файлов отпечатков, так и из набора кода, в основном на Ruby, который упрощает разработку, тестирование и использование содержащихся отпечатков. Для использования включённого Ruby-кода требуется свежая версия Ruby (2.31+), а также Rubygems и гем `bundler`. После установки этих зависимостей используйте следующие команды, чтобы получить последнюю версию исходного кода и установить все дополнительные зависимости.
```shell
$ git clone [email protected]:rapid7/recog.git
$ cd recog
$ bundle install
```
[^back to top](#recog-a-recognition-framework)
## Maturity
Обратите внимание: хотя сами XML-отпечатки достаточно стабильны и хорошо протестированы, кодовая база Ruby всё ещё довольно нова и может быстро меняться. Пожалуйста, свяжитесь с нами (research[at]rapid7.com), прежде чем использовать код Recog в каких-либо производственных проектах.
[^back to top](#recog-a-recognition-framework)
## Fingerprints
Отпечатки в Recog хранятся в XML-файлах, каждый из которых предназначен для сопоставления с определённой строкой ответа протокола или полем. Например, файл [ssh_banners.xml](https://github.com/rapid7/recog/blob/main/xml/ssh_banners.xml) может определить ОС, производителя, а иногда и аппаратный продукт, сопоставляя начальную строку баннера демона SSH.
Файл отпечатков представляет собой XML-документ следующего вида:
```xml
<fingerprints matches="ssh.banner">
<fingerprint pattern="^RomSShell_([\d\.]+)$">
<description>Allegro RomSShell SSH</description>
<example service.version="4.62">RomSShell_4.62</example>
<param pos="0" name="service.vendor" value="Allegro"/>
<param pos="0" name="service.product" value="RomSShell"/>
<param pos="1" name="service.version"/>
</fingerprint>
</fingerprints>
```
Первая строка всегда должна содержать объявление версии XML. Первым элементом всегда должен быть блок `fingerprints` с атрибутом `matches`, указывающим, какие данные должен сопоставлять этот файл отпечатков. Атрибут `matches` обычно имеет вид `protocol.field`.
Внутри элемента `fingerprints` должен быть один или несколько элементов `fingerprint`. Каждый `fingerprint` должен содержать атрибут `pattern`, в котором хранится регулярное выражение для сопоставления с данными. Необязательный атрибут `flags` может указывать, как интерпретировать регулярное выражение. См. [документацию Recog по `FLAG_MAP`](http://www.rubydoc.info/gems/recog/Recog/Fingerprint/RegexpFactory#FLAG_MAP-constant) для получения дополнительной информации.
Внутри отпечатка элемент `description` должен содержать читаемую человеком строку, описывающую этот отпечаток.
Должен присутствовать хотя бы один элемент `example`, однако предпочтительнее несколько. Эти элементы используются как часть тестового покрытия в `rspec`, которое проверяет, что предоставленные данные соответствуют указанному регулярному выражению. Кроме того, если отпечаток использует элементы `param` для извлечения значений полей из данных (описано далее), вы можете добавить эти ожидаемые извлечения в качестве атрибутов элементов `example`. В приведённом выше примере:
```xml
<example service.version="4.62">RomSShell_4.62</example>
```
проверяет, что `RomSShell_4.62` соответствует заданному регулярному выражению, и что значение `service.version` равно 4.62.
Строка `example` может быть закодирована в base64, чтобы разрешить использование непечатаемых символов. Для указания этого Recog к элементу `example` добавляется атрибут `_encoding` со значением `base64`. Текст в base64 длиннее 80 символов может быть перенесён на новые строки, как показано ниже, для улучшения читаемости.
```xml
<example _encoding="base64">
dGllczGEAAAAlQQWMS4yLjg0MC4xMTM1NTYuMS40LjgwMAQuZGF0YS5yZW1vdmVkLjCEAAAAK
AQdZG9tYWluQ29udHJvbGxlckZ1bmN0aW9uYWxpdHkxhAAAAAMEATc=
</example>
```
Кроме того, примеры могут быть помещены в каталог с тем же базовым именем, что и XML-файл, в том же каталоге, что и XML-файл:
```
xml/services.xml
xml/services/file1
xml/services/file2
...
```
Затем их можно загрузить с помощью атрибута `_filename`:
```xml
<example _filename="file1"/>
```
Это полезно для длинных примеров.
Элементы `param` содержат атрибут `pos`, указывающий, какое захваченное поле из `pattern` следует извлечь, или `0` для статической строки. Атрибут `name` — это ключ, который будет сообщён в случае успешного совпадения, а `value` будет либо статической строкой для значений `pos` равных `0`, либо отсутствовать и браться из захваченного поля.
Атрибут `value` поддерживает интерполяцию данных из других полей. Это часто полезно, когда значение для `hw.product` захватывается через регулярное выражение и затем используется в `os.product`.
Вот пример из `http_servers.xml`, где `hw.product` захватывается и используется повторно.
```xml
<fingerprint pattern="^Eltex (TAU-\d+[A-Z]*(?:\.IP)?)$">
<description>Eltex TAU model VoIP gateway</description>
<example hw.product="TAU-72">Eltex TAU-72</example>
<example hw.product="TAU-1.IP">Eltex TAU-1.IP</example>
<param pos="0" name="os.vendor" value="Eltex"/>
<param pos="0" name="os.product" value="{hw.product} Firmware"/>
<param pos="0" name="os.device" value="VoIP Gateway"/>
<param pos="0" name="hw.vendor" value="Eltex"/>
<param pos="1" name="hw.product"/>
<param pos="0" name="hw.device" value="VoIP Gateway"/>
</fingerprint>
```
Существует специальная обработка для временных атрибутов, имя которых начинается с `_tmp.`. Эти атрибуты могут использоваться для интерполяции, но не включаются в вывод. Это полезно, когда конкретное имя продукта непостоянно в различных баннерах, маркетинговых материалах поставщика или значениях NIST при попытке сгенерировать CPE. В таких случаях полезные части баннера можно извлечь и сформировать новое значение, не засоряя данные, выдаваемые при совпадении.
```xml
<fingerprint pattern="^foo baz switchThing-(\d{4})$">
<description>NetCorp NX series switches</description>
<example hw.product="NX8200">foo baz switchThing-8200</example>
<param pos="0" name="hw.vendor" value="NetCorp"/>
<param pos="0" name="hw.product" value="NX{_tmp.001}"/>
<param pos="2" name="_tmp.001"/>
</fingerprint>
```
Эти временные атрибуты не отслеживаются в `identifiers/fields.txt`.
[^back to top](#recog-a-recognition-framework)
### Testing matches
В следующих примерах используется `bin/recog_match` — простой инструмент командной строки на Ruby, который использует данные отпечатков Recog. Обычно перед запуском Recog требуется предварительная обработка, например, извлечение значений HTTP-заголовков. Все данные отпечатков можно найти в `xml/*.xml`.
#### ftp_banners
Определение FTP-серверов по ответу баннера сервера после подключения:
```
# Пример ввода в виде простого текста
echo -n '220 Microsoft FTP Service' | bin/recog_match xml/ftp_banners.xml -
# Пример команды с использованием nmap
nmap -sV -script=banner -p 21 192.168.123.13 | grep --color=never '_banner' | cut -d: -f2- | bin/recog_match xml/ftp_banners.xml -
# Пример вывода
MATCH: {"matched"=>"Microsoft FTP Server on Windows XP, 2003 or later without version", "service.vendor"=>"Microsoft", "service.product"=>"IIS", "service.family"=>"IIS", "service.cpe23"=>"cpe:/a:microsoft:iis:-", "os.vendor"=>"Microsoft", "os.family"=>"Windows", "os.product"=>"Windows", "os.cpe23"=>"cpe:/o:microsoft:windows:-", "host.name"=>"220", "service.protocol"=>"ftp", "fingerprint_db"=>"ftp.banner", "data"=>"220 Microsoft FTP Service"}
```
#### http_cookies
Использование значения HTTP-заголовка `Set-Cookie` для идентификации HTTP-сервера:
```
# Пример ввода в виде простого текста
echo 'laravel_session=eyJ...etc..etc...%3D; expires=Mon, 13-Mar-2023 16:48:58 GMT; Max-Age=7200; path=/; httponly; samesite=lax' | bin/recog_match xml/http_cookies.xml -
# Пример команды cURL
curl --silent -I http://localhost:9001 | grep --color=never -i '^Set-Cookie:' | cut -d: -f2- | bin/recog_match xml/http_cookies.xml -
# Пример вывода
MATCH: {"matched"=>"Laravel PHP web application framework", "service.vendor"=>"Laravel", "service.product"=>"Laravel", "service.cpe23"=>"cpe:/a:laravel:laravel:-", "service.protocol"=>"http", "fingerprint_db"=>"http_header.cookie", "data"=>"laravel_session=eyJ...etc..etc...%3D; expires=Mon, 13-Mar-2023 16:48:58 GMT; Max-Age=7200; path=/; httponly; samesite=lax"}
```
#### http_servers
Использование значения HTTP-заголовка `Server` для идентификации HTTP-сервера:
```
# Пример ввода в виде простого текста
echo -n 'Apache/2.4.38 (Debian)' | bin/recog_match xml/http_servers.xml -
# Пример команды cURL
curl --silent -I http://localhost:9001 | grep --color=never -i '^Server:' | cut -d: -f2- | bin/recog_match xml/http_servers.xml -
# Пример вывода
MATCH: {"matched"=>"Apache", "service.vendor"=>"Apache", "service.product"=>"HTTPD", "service.family"=>"Apache", "service.version"=>"2.4.38", "service.cpe23"=>"cpe:/a:apache:http_server:2.4.38", "apache.info"=>"(Debian)", "service.protocol"=>"http", "fingerprint_db"=>"http_header.server", "data"=>"Apache/2.4.38 (Debian)"}
```
#### favicons
Использование md5-суммы favicon для идентификации работающего сервиса:
```
# Пример ввода в виде простого текста
echo -n fe22dd2bb09daccf58256611ac491469 | bin/recog_match xml/favicons.xml -
# Пример команды cURL
curl --silent http://localhost:8000/favicon.ico | md5sum | awk '{ print $1 }' | bin/recog_match xml/favicons.xml -
# Пример вывода
MATCH: {"matched"=>"Drupal CMS", "service.vendor"=>"Drupal", "service.product"=>"CMS", "service.certainty"=>"0.5", "service.cpe23"=>"cpe:/a:drupal:drupal:-", "service.protocol"=>"", "fingerprint_db"=>"favicon.md5", "data"=>"fe22dd2bb09daccf58256611ac491469"}
```
#### http_wwwauth
Использование значения HTTP-заголовка `WWW-Authenticate` для идентификации HTTP-сервера:
```
# Пример ввода в виде простого текста
echo -n 'Basic realm="monit"' | bin/recog_match xml/http_wwwauth.xml -
# Пример команды cURL
curl --silent -I http://localhost:9001 | grep --color=never -i '^WWW-Authenticate:' | cut -d: -f2- | bin/recog_match xml/http_wwwauth.xml -
# Пример вывода
MATCH: {"matched"=>"Minot", "service.vendor"=>"Tildeslash", "service.product"=>"Monit", "service.cpe23"=>"cpe:/a:tildeslash:monit:-", "service.protocol"=>"http", "fingerprint_db"=>"http_header.wwwauth", "data"=>"Basic realm=\"monit\""}
```
#### tls_jarm
Идентификация TLS-серверов по ответу сервера на 10 пакетов TLS Client Hello. Отпечаток основан на https://github.com/salesforce/jarm
```
# Пример ввода в виде простого текста
echo -n 07d14d16d21d21d07c42d43d000000f50d155305214cf247147c43c0f1a823 | bin/recog_match xml/jarm.xml -
# Пример команды с использованием JARM от Salesforce против работающего слушателя Metasploit
python3 $code/jarm/jarm.py -p 8443 192.168.123.1 | grep --color=never 'JARM: ' | awk -F: '{ print $2 }' | bin/recog_match xml/tls_jarm.xml -
# Пример вывода
MATCH: {"matched"=>"Metasploit listener", "service.vendor"=>"Rapid7", "service.product"=>"Metasploit", "service.cpe23"=>"cpe:/a:rapid7:metasploit:-", "service.protocol"=>"tls", "fingerprint_db"=>"tls.jarm", "data"=>"07d14d16d21d21d07c42d43d000000f50d155305214cf247147c43c0f1a823"}
```
## Contributing
Пользователи и сопровождающие Recog будут весьма признательны за любой ваш вклад в проект. Рекомендации и инструкции см. в [CONTRIBUTING.MD](https://github.com/rapid7/recog/blob/main/CONTRIBUTING.md)
[^back to top](#recog-a-recognition-framework)