
Reconhecimento de padrões para hosts, serviços e conteúdo
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 para obter mais informações.
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 agora contém o conteúdo do Recog, e o repositório 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.
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 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
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.
$ git clone [email protected]:rapid7/recog.git
$ cd recog
$ bundle install
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.
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 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:
<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 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:
<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.
<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:
<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 dehttp_servers.xml onde hw.product é capturado e reutilizado.
<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.
<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.
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.
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"}
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"}
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)"}
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"}
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\""}
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"}
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
| Recurso ✨ | rapid7/recog-ruby | rapid7/recog-java | runZeroInc/recog-go |
|---|
| Ferramenta CLI de verificação de fingerprints | ✅ | ✅ | ✅ |
| Ferramenta CLI de correspondência de fingerprints | ✅ | ✅ | |
| Suporta exemplos codificados em base64 | ✅ | ✅ | ✅ |
| Suporta exemplos externos baseados em sistema de arquivos | ✅ | ✅ | ✅ |
| Interpolação de parâmetro CPE na correspondência de fingerprints | ✅ | ✅ | ✅ |