
Pattern recognition for hosts, services, and content
Recog est un framework pour identifier les produits, services, systèmes d'exploitation et matériels en faisant correspondre des empreintes digitales avec les données renvoyées par diverses sondes réseau. Recog simplifie l'extraction d'informations utiles à partir de bannières de serveurs web, de champs de description système SNMP, et bien plus encore.
Recog est open source, veuillez consulter le fichier LICENSE pour plus d'informations.
Le 31 mars 2022, le contenu de Recog (fichiers d'empreintes XML et utilitaires) a été séparé de l'implémentation de la bibliothèque du framework Recog. Le dépôt d'origine Recog contient désormais le contenu Recog et le dépôt Recog-Ruby contient l'implémentation en langage Ruby. Le contenu Recog est inclus dans Recog-Ruby en tant que sous-module git et est imbriqué sous le répertoire recog. Toutes les versions de la gemme Recog post-split égales ou supérieures à 3.0.0 : 1. contiendront le répertoire d'empreintes XML sous le répertoire recog, et 2. incluront uniquement l'outil recog_match car les autres outils sont axés sur la gestion des empreintes.
Parallèlement à la division du dépôt, la branche par défaut a été renommée de master à main. Tout clone créé avant ces modifications devra être mis à jour manuellement dans votre environnement local. Si vous avez un fork, accédez aux paramètres de votre fork et suivez les instructions sur le renommage d'une branche pour changer la branche par défaut en main.
git branch -m master main
git fetch origin
git branch -u origin/main main
git remote set-head origin -a
En option, exécutez la commande suivante pour supprimer les références de suivi de l'ancien nom de branche.
# dry-run pour confirmer les références obsolètes qui seront supprimées avant de continuer
git remote prune origin --dry-run
git remote prune origin
Si vous utilisiez auparavant la branche de suivi amont upstream-master, exécutez les commandes suivantes pour supprimer l'ancienne branche et créer une nouvelle branche de suivi amont.
git branch -d upstream-master
git checkout -b upstream-main --track upstream/main
En option, exécutez la commande suivante pour supprimer les références de suivi de l'ancien nom de branche amont.
# dry-run pour confirmer les références obsolètes qui seront supprimées avant de continuer
git remote prune upstream --dry-run
git remote prune upstream
Recog se compose à la fois de fichiers d'empreintes XML et d'un ensemble de code, principalement en Ruby, qui facilite le développement, les tests et l'utilisation des empreintes contenues. Pour utiliser le code Ruby inclus, une version récente de Ruby (2.31+) est requise, ainsi que Rubygems et la gemme bundler. Une fois ces dépendances en place, utilisez les commandes suivantes pour récupérer le dernier code source et installer les dépendances supplémentaires.
$ git clone [email protected]:rapid7/recog.git
$ cd recog
$ bundle install
Veuillez noter que bien que les empreintes XML elles-mêmes soient assez stables et bien testées, la base de code Ruby est encore relativement nouvelle et susceptible de changer rapidement. Veuillez nous contacter (research[at]rapid7.com) avant d'utiliser le code Recog dans des projets de production.
Les empreintes digitales de Recog sont stockées dans des fichiers XML, chacun étant conçu pour correspondre à une chaîne de réponse ou un champ de protocole spécifique. Par exemple, le fichier ssh_banners.xml peut déterminer le système d'exploitation, le fournisseur, et parfois le produit matériel en faisant correspondre la chaîne de bannière initiale du démon SSH.
Un fichier d'empreintes se compose d'un document XML comme celui-ci :
<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>
La première ligne doit toujours consister en la déclaration de version XML. Le premier élément doit toujours être un bloc fingerprints avec un attribut matches indiquant à quelles données ce fichier d'empreintes est censé correspondre. L'attribut matches est généralement sous la forme protocol.field.
À l'intérieur de l'élément fingerprints, il doit y avoir un ou plusieurs éléments fingerprint. Chaque fingerprint doit contenir un attribut pattern, qui contient l'expression régulière à utiliser pour la correspondance avec les données. Un attribut optionnel flags peut être spécifié pour contrôler la façon dont l'expression régulière est interprétée. Voir la documentation Recog pour FLAG_MAP pour plus d'informations.
À l'intérieur de l'empreinte, un élément description doit contenir une chaîne lisible par l'homme décrivant cette empreinte.
Au moins un élément example doit être présent, mais plusieurs éléments example sont préférés. Ces éléments sont utilisés dans le cadre de la couverture de test présente dans rspec qui valide que les données fournies correspondent à l'expression régulière spécifiée. De plus, si l'empreinte utilise les éléments param pour extraire les valeurs de champ des données (décrit ci-après), vous pouvez ajouter ces extractions attendues comme attributs pour les éléments example. Dans l'exemple ci-dessus, ceci :
<example service.version="4.62">RomSShell_4.62</example>
teste que RomSShell_4.62 correspond à l'expression régulière fournie et que la valeur de service.version est 4.62.
La chaîne example peut être encodée en base64 pour permettre l'utilisation de caractères non imprimables. Pour signaler cela à Recog, un attribut _encoding avec la valeur base64 est ajouté à l'élément example. Le texte encodé en base64 de plus de 80 caractères peut être coupé avec des sauts de ligne comme indiqué ci-dessous pour faciliter la lecture.
<example _encoding="base64">
dGllczGEAAAAlQQWMS4yLjg0MC4xMTM1NTYuMS40LjgwMAQuZGF0YS5yZW1vdmVkLjCEAAAAK
AQdZG9tYWluQ29udHJvbGxlckZ1bmN0aW9uYWxpdHkxhAAAAAMEATc=
</example>
De plus, les exemples peuvent être placés dans un répertoire portant le même nom de base que le fichier XML, dans le même répertoire que le fichier XML :
xml/services.xml
xml/services/file1
xml/services/file2
...
Ils peuvent ensuite être chargés en utilisant l'attribut _filename :
<example _filename="file1"/>
Ceci est utile pour les exemples longs.
Les éléments param contiennent un attribut pos, qui indique quel champ de capture du pattern doit être extrait, ou 0 pour une chaîne statique. L'attribut name est la clé qui sera signalée en cas de correspondance réussie et la value sera soit une chaîne statique pour les valeurs de pos de 0, soit absente et prise du champ capturé.
L'attribut value prend en charge l'interpolation de données à partir d'autres champs. Ceci est souvent utile lors de la capture de la valeur pour hw.product via regex et de la réutilisation de cette valeur dans os.product.
Voici un exemple de http_servers.xml où hw.product est capturé et réutilisé.
<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>
Il existe un traitement spécial pour les attributs temporaires dont le nom commence par _tmp.. Ces attributs peuvent être utilisés pour l'interpolation mais ne sont pas émis dans la sortie. Ceci est utile lorsqu'un nom de produit particulier est incohérent dans diverses bannières, dans le marketing des fournisseurs ou avec les valeurs NIST lors de la génération de CPE. Dans ces cas, les parties utiles de la bannière peuvent être extraites et une nouvelle valeur peut être créée sans encombrer les données émises par une correspondance.
<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>
Ces attributs temporaires ne sont pas suivis dans identifiers/fields.txt.
Les exemples suivants utilisent bin/recog_match, un outil en ligne de commande Ruby simple qui utilise les données d'empreintes de Recog. Un prétraitement est généralement nécessaire avant d'exécuter Recog, par exemple l'extraction des valeurs d'en-tête HTTP, etc. Toutes les données d'empreintes se trouvent dans xml/*.xml.
Empreinte des serveurs FTP basée sur la réponse de bannière du serveur après connexion :
# Exemple d'entrée en texte brut
echo -n '220 Microsoft FTP Service' | bin/recog_match xml/ftp_banners.xml -
# Exemple de commande utilisant 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 -
# Exemple de sortie
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"}
Utilisation de la valeur de l'en-tête HTTP Set-Cookie pour empreindre un serveur HTTP :
# Exemple d'entrée en texte brut
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 -
# Exemple de commande cURL
curl --silent -I http://localhost:9001 | grep --color=never -i '^Set-Cookie:' | cut -d: -f2- | bin/recog_match xml/http_cookies.xml -
# Exemple de sortie
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"}
Utilisation de la valeur de l'en-tête HTTP Server pour empreindre un serveur HTTP :
# Exemple d'entrée en texte brut
echo -n 'Apache/2.4.38 (Debian)' | bin/recog_match xml/http_servers.xml -
# Exemple de commande cURL
curl --silent -I http://localhost:9001 | grep --color=never -i '^Server:' | cut -d: -f2- | bin/recog_match xml/http_servers.xml -
# Exemple de sortie
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)"}
Utilisation de la somme md5 d'un favicon pour identifier un service en cours d'exécution :
# Exemple d'entrée en texte brut
echo -n fe22dd2bb09daccf58256611ac491469 | bin/recog_match xml/favicons.xml -
# Exemple de commande cURL
curl --silent http://localhost:8000/favicon.ico | md5sum | awk '{ print $1 }' | bin/recog_match xml/favicons.xml -
# Exemple de sortie
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"}
Utilisation de la valeur de l'en-tête HTTP WWW-Authenticate pour empreindre un serveur HTTP :
# Exemple d'entrée en texte brut
echo -n 'Basic realm="monit"' | bin/recog_match xml/http_wwwauth.xml -
# Exemple de commande cURL
curl --silent -I http://localhost:9001 | grep --color=never -i '^WWW-Authenticate:' | cut -d: -f2- | bin/recog_match xml/http_wwwauth.xml -
# Exemple de sortie
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\""}
Empreinte des serveurs TLS basée sur la réponse du serveur à 10 paquets TLS Client Hello. Empreinte basée sur https://github.com/salesforce/jarm
# Exemple d'entrée en texte brut
echo -n 07d14d16d21d21d07c42d43d000000f50d155305214cf247147c43c0f1a823 | bin/recog_match xml/jarm.xml -
# Exemple de commande utilisant JARM de Salesforce contre un écouteur Metasploit en cours d'exécution
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 -
# Exemple de sortie
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"}
Les utilisateurs et mainteneurs de Recog apprécieraient beaucoup toute contribution que vous pourriez apporter au projet. Pour les directives et instructions, veuillez consulter CONTRIBUTING.MD
| Fonctionnalité ✨ | rapid7/recog-ruby | rapid7/recog-java | runZeroInc/recog-go |
|---|
| Outil en ligne de commande de vérification des empreintes | ✅ | ✅ | ✅ |
| Outil en ligne de commande de correspondance des empreintes | ✅ | ✅ | |
| Prise en charge des exemples encodés en base64 | ✅ | ✅ | ✅ |
| Prise en charge des exemples externes basés sur le système de fichiers | ✅ | ✅ | ✅ |
| Interpolation des paramètres CPE de correspondance des empreintes | ✅ | ✅ | ✅ |