
Reconhecimento de padrões para hosts, serviços e conteúdo
# Recog: Um Framework de Reconhecimento
[](https://github.com/rapid7/recog/actions/workflows/ci.yml)
[](https://github.com/rapid7/recog/actions/workflows/verify.yml)
Recog é um framework para identificar produtos, serviços, sistemas operacionais e hardware por meio da correspondência de fingerprints com dados retornados por diversas sondas de rede. O Recog torna simples extrair informações úteis de banners de servidores web, campos de descrição de sistema do SNMP e muito mais.
O Recog é open source; consulte o arquivo [LICENSE](https://github.com/rapid7/recog/blob/main/LICENSE) para obter mais informações.
## Índice
1. [Separação do repositório](#repository-split)
1. [Renomeação do branch padrão](#default-branch-rename)
1. [Implementações da biblioteca Recog por linguagem](#recog-library-language-implementations)
1. [Paridade de recursos](#feature-parity)
1. [Instalação](#installation)
1. [Maturidade](#maturity)
1. [Fingerprints](#fingerprints)
1. [Testando correspondências](#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. [Contribuindo](#contributing)
## Separação do repositório
Em 31 de março de 2022, o conteúdo do Recog - arquivos XML de fingerprints e utilitários - foi separado da implementação da biblioteca do framework Recog. O repositório original [Recog](https://github.com/rapid7/recog) agora contém o conteúdo do Recog, e o repositório [Recog-Ruby](https://github.com/rapid7/recog-ruby) contém a implementação em Ruby. O conteúdo do Recog é incluído no Recog-Ruby como um submódulo git e fica aninhado no diretório `recog`. Todas as versões da gem Recog pós-separação, iguais ou superiores a 3.0.0, irão: 1. conter o diretório de fingerprints XML sob o diretório `recog` e 2. incluir apenas a ferramenta `recog_match`, uma vez que as demais ferramentas são focadas no gerenciamento de fingerprints.
[^voltar ao topo](#recog-a-recognition-framework)
### Renomeação do branch padrão
Junto com a separação do repositório, o branch padrão foi renomeado de `master` para `main`. Qualquer clone criado antes dessas alterações precisará ser atualizado manualmente no seu ambiente local. Se você tiver um fork, navegue até as configurações do seu fork e siga as instruções sobre [renomear um branch](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-branches-in-your-repository/renaming-a-branch) para alterar o branch padrão para `main`.
```
git branch -m master main
git fetch origin
git branch -u origin/main main
git remote set-head origin -a
```
Opcionalmente, execute o seguinte comando para remover as referências de rastreamento ao nome do branch antigo.
```
# dry-run to confirm stale references that will be deleted before proceeding
git remote prune origin --dry-run
git remote prune origin
```
Se você usou anteriormente o branch de rastreamento upstream `upstream-master`, execute os seguintes comandos para remover o branch antigo e criar um novo branch de rastreamento upstream.
```
git branch -d upstream-master
git checkout -b upstream-main --track upstream/main
```
Opcionalmente, execute o seguinte comando para remover as referências de rastreamento ao nome do branch upstream antigo.
```
# dry-run to confirm stale references that will be deleted before proceeding
git remote prune upstream --dry-run
git remote prune upstream
```
[^voltar ao topo](#recog-a-recognition-framework)
## Implementações da biblioteca Recog por linguagem
* 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)
[^voltar ao topo](#recog-a-recognition-framework)
### Paridade de recursos
| Recurso :sparkles: | rapid7/recog-ruby | rapid7/recog-java | runZeroInc/recog-go |
|---------------------------------------------|:------------------:|:------------------:|:-------------------:|
| Ferramenta CLI de verificação de fingerprints | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Ferramenta CLI de correspondência de fingerprints | :white_check_mark: | | :white_check_mark: |
| Suporta exemplos codificados em base64 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Suporta exemplos externos baseados em sistema de arquivos | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Interpolação de parâmetro CPE na correspondência de fingerprints | :white_check_mark: | :white_check_mark: | :white_check_mark: |
[^voltar ao topo](#recog-a-recognition-framework)
## Instalação
O Recog consiste tanto em arquivos XML de fingerprints quanto em uma variedade de código, principalmente em Ruby, que facilita o desenvolvimento, o teste e o uso dos fingerprints contidos. Para usar o código Ruby incluído, é necessária uma versão recente do Ruby (2.31+), juntamente com Rubygems e a gem `bundler`. Uma vez que essas dependências estejam instaladas, use os seguintes comandos para obter o código-fonte mais recente e instalar quaisquer dependências adicionais.
```shell
$ git clone [email protected]:rapid7/recog.git
$ cd recog
$ bundle install
```
[^voltar ao topo](#recog-a-recognition-framework)
## Maturidade
Observe que, embora os próprios fingerprints XML sejam bastante estáveis e bem testados, a base de código Ruby ainda é relativamente nova e sujeita a mudanças rápidas. Entre em contato conosco (research[at]rapid7.com) antes de utilizar o código do Recog em qualquer projeto em produção.
[^voltar ao topo](#recog-a-recognition-framework)
## Fingerprints
Os fingerprints no Recog são armazenados em arquivos XML, cada um projetado para corresponder a uma string ou campo específico de resposta de protocolo. Por exemplo, o arquivo [ssh_banners.xml](https://github.com/rapid7/recog/blob/main/xml/ssh_banners.xml) pode determinar o sistema operacional, o fornecedor e, às vezes, o produto de hardware por meio da correspondência com a string inicial do banner do daemon SSH.
Um arquivo de fingerprint consiste em um documento XML como o seguinte:
```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>
```
A primeira linha deve consistir sempre na declaração da versão do XML. O primeiro elemento deve ser sempre um bloco `fingerprints` com um atributo `matches` indicando a quais dados este arquivo de fingerprint deve corresponder. O atributo `matches` normalmente está na forma `protocol.field`.
Dentro do elemento `fingerprints`, deve haver um ou mais elementos `fingerprint`. Cada `fingerprint` deve conter um atributo `pattern`, que contém a expressão regular a ser usada para corresponder aos dados. Um atributo opcional `flags` pode ser especificado para controlar como a expressão regular deve ser interpretada. Consulte [a documentação do Recog para `FLAG_MAP`](http://www.rubydoc.info/gems/recog/Recog/Fingerprint/RegexpFactory#FLAG_MAP-constant) para obter mais informações.
Dentro do fingerprint, um elemento `description` deve conter uma string legível por humanos que descreve este fingerprint.
Pelo menos um elemento `example` deve estar presente; no entanto, vários elementos `example` são preferíveis. Esses elementos são usados como parte da cobertura de testes presente no `rspec`, que valida se os dados fornecidos correspondem à expressão regular especificada. Além disso, se o fingerprint estiver usando os elementos `param` para extrair valores de campos dos dados (descrito a seguir), você pode adicionar essas extrações esperadas como atributos dos elementos `example`. No exemplo acima, isto:
```xml
<example service.version="4.62">RomSShell_4.62</example>
```
testa se `RomSShell_4.62` corresponde à expressão regular fornecida e se o valor de `service.version` é 4.62.
A string `example` pode ser codificada em base64 para permitir o uso de caracteres não imprimíveis. Para sinalizar isso ao Recog, um atributo `_encoding` com o valor `base64` é adicionado ao elemento `example`. Texto codificado em Base64 com mais de 80 caracteres pode ser quebrado em novas linhas, como mostrado abaixo, para facilitar a leitura.
```xml
<example _encoding="base64">
dGllczGEAAAAlQQWMS4yLjg0MC4xMTM1NTYuMS40LjgwMAQuZGF0YS5yZW1vdmVkLjCEAAAAK
AQdZG9tYWluQ29udHJvbGxlckZ1bmN0aW9uYWxpdHkxhAAAAAMEATc=
</example>
```
Além disso, os exemplos podem ser colocados em um diretório com o mesmo nome base do arquivo XML, no mesmo diretório do arquivo XML:
xml/services.xml
xml/services/file1
xml/services/file2
...
Eles podem então ser carregados usando o atributo `_filename`:
```xml
<example _filename="file1"/>
```
Isso é útil para exemplos longos.
Os elementos `param` contêm um atributo `pos`, que indica qual campo de captura do `pattern` deve ser extraído, ou `0` para uma string estática. O atributo `name` é a chave que será reportada em caso de correspondência bem-sucedida, e o `value` será uma string estática para valores de `pos` iguais a `0` ou estará ausente e será obtido do campo capturado.
O atributo `value` suporta interpolação de dados de outros campos. Isso é frequentemente útil ao capturar o valor de `hw.product` via regex e reutilizar esse valor em `os.product`.
Aqui está um exemplo de`http_servers.xml` onde `hw.product` é capturado e reutilizado.
```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>
```
Há um tratamento especial para atributos temporários cujo nome começa com `_tmp.`. Esses atributos podem ser usados para interpolação, mas não são emitidos na saída. Isso é útil quando um nome de produto específico é inconsistente em vários banners, no marketing do fornecedor ou com os valores do NIST ao tentar gerar CPEs. Nesses casos, as partes úteis do banner podem ser extraídas e um novo valor pode ser criado sem poluir os dados emitidos por uma correspondência.
```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>
```
Esses atributos temporários não são rastreados em `identifiers/fields.txt`.
[^voltar ao topo](#recog-a-recognition-framework)
### Testando correspondências
Os exemplos a seguir fazem uso de `bin/recog_match`, uma ferramenta simples de linha de comando em Ruby que usa os dados de fingerprints do Recog. O pré-processamento geralmente é necessário antes de executar o Recog, ou seja, extrair valores de cabeçalhos HTTP, etc. Todos os dados de fingerprints podem ser encontrados em `xml/*.xml`.
#### ftp_banners
Fingerprint de servidores FTP com base na resposta do banner do servidor após a conexão:
# Example plaintext input
echo -n '220 Microsoft FTP Service' | bin/recog_match xml/ftp_banners.xml -
# Example command using 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 -
# Example output
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
Usando o valor do cabeçalho HTTP `Set-Cookie` para fazer fingerprint de um servidor HTTP:
# Example plaintext input
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 -
# Example cURL command
curl --silent -I http://localhost:9001 | grep --color=never -i '^Set-Cookie:' | cut -d: -f2- | bin/recog_match xml/http_cookies.xml -
# Example output
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
Usando o valor do cabeçalho HTTP `Server` para fazer fingerprint de um servidor HTTP:
# Example plaintext input
echo -n 'Apache/2.4.38 (Debian)' | bin/recog_match xml/http_servers.xml -
# Example cURL command
curl --silent -I http://localhost:9001 | grep --color=never -i '^Server:' | cut -d: -f2- | bin/recog_match xml/http_servers.xml -
# Example output
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
Usando o md5sum de um favicon para identificar um serviço em execução:
# Example plaintext input
echo -n fe22dd2bb09daccf58256611ac491469 | bin/recog_match xml/favicons.xml -
# Example cURL command
curl --silent http://localhost:8000/favicon.ico | md5sum | awk '{ print $1 }' | bin/recog_match xml/favicons.xml -
# Example output
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
Usando o valor do cabeçalho HTTP `WWW-Authenticate` para fazer fingerprint de um servidor HTTP:
# Example plaintext input
echo -n 'Basic realm="monit"' | bin/recog_match xml/http_wwwauth.xml -
# Example cURL command
curl --silent -I http://localhost:9001 | grep --color=never -i '^WWW-Authenticate:' | cut -d: -f2- | bin/recog_match xml/http_wwwauth.xml -
# Example output
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
Fingerprint de servidores TLS com base na resposta do servidor a 10 pacotes TLS Client Hello. Fingerprint baseado em https://github.com/salesforce/jarm
# Example plaintext input
echo -n 07d14d16d21d21d07c42d43d000000f50d155305214cf247147c43c0f1a823 | bin/recog_match xml/jarm.xml -
# Example command using Salesforce's JARM against a running Metasploit listener
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 -
# Example output
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"}
## Contribuindo
Os usuários e mantenedores do Recog agradeceriam muito qualquer contribuição que você possa fazer ao projeto. Para diretrizes e instruções, consulte [CONTRIBUTING.MD](https://github.com/rapid7/recog/blob/main/CONTRIBUTING.md)
[^voltar ao topo](#recog-a-recognition-framework)