
Dans le domaine de la cybersécurité, identifier et caractériser précisément les serveurs web est essentiel pour la détection des menaces, l'évaluation des vulnérabilités et la cartographie du réseau. Nous présentons HTTP-Basma, un nouvel algorithme de fingerprinting actif qui révèle des profils de serveurs uniques grâce à une approche multicouche.
HTTP-Basma est en ligne sur https://httpbasma.netomize.ca/
Dans le domaine de la cybersécurité, identifier et caractériser avec précision les serveurs web est crucial pour la détection des menaces, l'évaluation des vulnérabilités et la cartographie des réseaux. Nous présentons HTTP-Basma, un nouvel algorithme d'empreinte active qui révèle des profils de serveurs uniques grâce à une approche multicouche, répondant ainsi à ce défi.
Fonctionnalités clés : Requêtes élaborées, réponses révélatrices : HTTP-Basma envoie 8 sondes HTTP méticuleusement conçues, suscitant des réponses distinctives qui reflètent les configurations du serveur. Double hachage pour la polyvalence. L'algorithme génère deux hachages :
Regroupement et chasse : ces hachages permettent le regroupement de serveurs, l'identification de serveurs uniques ou similaires, et la poursuite d'acteurs malveillants avec une confiance accrue.
Conception modulaire pour l'extension : l'architecture de l'algorithme favorise l'ajout de nouvelles variantes de hachage, encourageant la collaboration et l'adaptabilité.
Dans cet article, nous passons d'abord en revue les travaux notables existants sur l'empreinte HTTP, puis explorons la fonctionnalité, la conception, l'architecture et les résultats de l'algorithme. De plus, nous présenterons des résultats convaincants issus du balayage des 1 million de sites Majestic les plus populaires, notamment l'identification et le regroupement des serveurs C&C HTTP pour diverses familles de logiciels malveillants.
L'idée centrale de l'algorithme de HTTP-Basma consiste à envoyer 8 requêtes HTTP spécialement conçues avec des exigences variables afin d'obtenir différentes réponses du serveur. Une fois la réponse du serveur récupérée, la ligne d'état HTTP est disséquée chirurgicalement pour tous ses éléments et encodée de manière optimale. De plus, certains en-têtes de la réponse du serveur sont également vérifiés pour l'encodage.
Les requêtes qu'il envoie sont de ces types :
Après chaque requête, la réponse du serveur est analysée pour extraire des en-têtes spécifiques et leurs valeurs. Ces données extraites subissent un traitement supplémentaire, notamment la dissection et l'encodage, afin de générer une empreinte réversible.
Les détails techniques complets du fonctionnement de l'algorithme se trouvent dans le document ci-joint.
Cette philosophie de conception modulaire traite l'empreinte de chaque requête comme un élément de base, permettant un refactoring élégant, avec la possibilité d'ajouter et de retirer l'empreinte de n'importe quelle requête.
Exemples d'empreintes :
- verbosus fp: 011420958a0014514bd5221420958a221420958a221420958a2200001420958a22000000001f
- pacto fp: 02464ae8b7d86f82c9918e2c2b9d6b91
- note: false-positive rate (72/986,910)
- verbosus fp: 01142494d60914514bd522142494d6221420958a701420958a220000140e04922032c37f1609
- pacto fp: 020769322f3d94ac2f258ddf5ce08502
- note-1: false-positive rate 0
- note-2: tevedadav.site/43.209.165.126:443 (TLS)
- sample-(sha-256): 9aa1dec8dd12f8adc7fc1274e1958f3613450109ee8b4ec6442a0fcf06df0972
- verbosus fp: 01140a85e40014512f3612140a85e422140a85e422140a85e4220000140a85e4220000000001
- pacto fp: 0207292309a7a7e798e417d69df5f2a5
- note: false-positive rate (73/986,910)
- verbosus fp: 01140a85e4001320958a22142494d62214254c5e2214254c5e22080014254c5e220000000000
- pacto fp: 0202be780e1eaae0eaa6184e20c909b6
- note: false-positive rate (4/986,910)
- verbosus fp: 01140a85e4011320958a22142494d67214254c5e2214254c5e22080014254c5e220000000000
- pacto fp: 02cc5be6d05192e17de041538508bc22
- note: false-positive rate (38/986,910)
- verbosus fp: 01140a85e40914514bd522140a85e4721420958a701420958a220800140a85e4720000001609
- pacto fp: 0221b4e46bbd0e5c037f5a852ca3fdc0
- note: false-positive rate (6/986,910)
HTTP-Basma est un outil C++ que j'ai développé pour démontrer le côté pratique et la viabilité de cet algorithme. Il s'appuie sur la bibliothèque de Chilkat pour toutes les interactions de sockets HTTP et utilise d'autres classes de support de la bibliothèque. De plus, l'outil inclut une fonction de démangling (demangler) qui peut disséquer et inverser le hachage flou verbosus, produisant un objet JSON complet, ainsi qu'une fonction de comparaison qui affiche les différences entre deux empreintes verbosus.
Notez que certains résultats de l'outil peuvent utiliser des numéros de sonde légèrement différents, mais l'ordre sous-jacent reste cohérent : P1->P1, P2->P2, P3->P3, P4->P4, P->P5, P6->P6F, P7->P6L, P8->P7a.
Usage:
HTTP-Basma [OPTION...]
-d, --domain arg domains/IPs (you may query multiple domains, comma separated)
-p, --port arg port number
-s, --ssl does the HTTP connection have to be carried over SSL/TLS?
-q, --qpath check domain with url path included (not recommended)
-w, --redirect enable/disable HTTP redirects. If disabled/false, only the next redirect is followed,
otherwise, all redirects are followed (default: true)
-t, --ctimeout arg socket connection timeout value in seconds (default: 1)
-g, --rtimeout arg socket read (from the server) timeout value in seconds (default: 1)
-e, --sleep arg the duration (in milliseconds) to pause between each request (default: 100)
-x, --proxy arg proxy config: <"socks4|socks5|http">,<domain>,<port>,<bool:direct_tls>,<login>,<pass>
all values are comma-separated. <direct_tls> is ignored with a non-HTTP proxy
-f, --file arg file with list of domains/IPs (requires "-c/--csv" or "-j/--json")
-P, --parallel Scan list of domains passed via the "-f/--file" option in parallel
-c, --csv save to csv file; if the option 'n' is not specified, the CSV filename will be auto
generated
-n, --csvfile arg name of the CSV file
-j, --json save to json file; if the option 'l' is not specified, the JSON filename will be auto
generated
-l, --jsonfile arg name of the JSON file
-r, --saveh save request response headers
-o, --pjson display fingerprint dissection to the console as a JSON object
-i, --demangle_json arg demangle a fingerprint into a detailed json format (you can have more than one, comma
separated)
-u, --demangle_txt arg output a concise text format of the fingerprint, comma-separated for multiple results
-C, --compare arg compare two verbosus fingerprints (comma-separated)
-a, --pacto arg obtain the Pacto fingerprint using Verbosus
-h, --help print usage
Lors d'une requête vers un domaine/IP donné, la réponse peut être enregistrée dans un fichier CSV ou JSON avec une multitude d'informations sur les en-têtes de réponse du serveur et l'empreinte unique de chaque sonde.
Par exemple, pour obtenir l'empreinte du serveur https://google.com, enregistrer les résultats dans un fichier JSON et CSV, tout en sauvegardant les en-têtes de réponse HTTP de chaque sonde :
HTTPBasma.exe -d https://google.com --json --csv --saveh
Dans le dossier Output, vous trouverez le fichier CSV google_hb_results_2026-05-19_08-35-38_am.csv et le fichier JSON google_hb_results_2026-05-19_08-35-38_am.json.
La fonction de démangling "-i/--demangle_json" de l'outil prend une empreinte verbosus et reconstruit les attributs de chaque sonde, produisant un objet JSON complet. Notamment, lors de la tentative d'inversion des hachages FNV-1a, le démangleur utilise deux bases de données locales : options.csv pour les méthodes HTTP autorisées et status_line_db.csv pour les phrases de raison de la ligne d'état. Si l'un de ces fichiers de base de données est manquant, la fonction d'inversion de hachage correspondante est automatiquement désactivée. Ces bases de données ont été compilées à partir d'un balayage des 1 million de sites Majestic les plus populaires.
Le démangling de l'empreinte verbosus, pour le domaine example.com :
HTTPBasma.exe --demangle_json 01140a85e40014514bd522142494d67214254c5e721420958a22020214254c5e720000001609
{
"type": "verbosus",
"fp": "01140a85e40014514bd522142494d67214254c5e721420958a22020214254c5e720000001609",
"p1": {
"type": "get_normal",
"fp": "140a85e400",
"status_line": {
"http_version": {
"fp": "14",
"val_cmt": "HTTP/1.1"
},
"status_code": {
"fp": "0a",
"val_cmt": "200"
},
"http_reason": {
"fp": "85e4",
"val_cmt": "OK"
},
"sl_reversed_db": {
"http_version": "HTTP/1.1",
"status_code": [
200,
404,
403,
500,
204,
999,
888,
603
],
"http_reason": "OK"
}
},
"sts_hdr": {
"fp": "00",
"cmt": "this header is not used"
}
},
"p2": {
"type": "get_invalid_ver_nb",
"fp": "14514bd522",
"status_line": {
"http_version": {
"fp": "14",
"val_cmt": "HTTP/1.1"
},
"status_code": {
"fp": "51",
"val_cmt": "505"
},
"http_reason": {
"fp": "4bd5",
"val_cmt": "HTTP Version Not Supported"
},
"sl_reversed_db": {
"http_version": "HTTP/1.1",
"status_code": [
505
],
"http_reason": "HTTP Version Not Supported"
}
},
"cont_len_hdr": {
"fp": "22",
"name": "Content-Length",
"value": ">1",
"cmt": "content-length/transfer-encoding:chunked header is present with either of the size values: [0,1,>1]"
},
"cnx": {
"ka": false,
"c": true
}
},
"p3": {
"type": "get_rnd_resource",
"fp": "142494d672",
"status_line": {
"http_version": {
"fp": "14",
"val_cmt": "HTTP/1.1"
},
"status_code": {
"fp": "24",
"val_cmt": "404"
},
"http_reason": {
"fp": "94d6",
"val_cmt": "Not Found"
},
"sl_reversed_db": {
"http_version": "HTTP/1.1",
"status_code": [
404,
403,
501,
410,
204,
400,
200,
418
],
"http_reason": "Not Found"
}
},
"cont_len_hdr": {
"fp": "72",
"name": "Transfer-Encoding",
"value": ">1",
"cmt": "content-length/transfer-encoding:chunked header is present with either of the size values: [0,1,>1]"
},
"cnx": {
"ka": true,
"c": false
}
},
"p4": {
"type": "get_rnd_verb",
"fp": "14254c5e72",
"status_line": {
"http_version": {
"fp": "14",
"val_cmt": "HTTP/1.1"
},
"status_code": {
"fp": "25",
"val_cmt": "405"
},
"http_reason": {
"fp": "4c5e",
"val_cmt": "Method Not Allowed"
},
"sl_reversed_db": {
"http_version": "HTTP/1.1",
"status_code": [
405,
403,
204,
418,
404
],
"http_reason": "Method Not Allowed"
}
},
"cont_len_hdr": {
"fp": "72",
"name": "Transfer-Encoding",
"value": ">1",
"cmt": "content-length/transfer-encoding:chunked header is present with either of the size values: [0,1,>1]"
},
"cnx": {
"ka": true,
"c": false
}
},
"p5": {
"type": "get_lowercase_verb",
"fp": "1420958a22",
"status_line": {
"http_version": {
"fp": "14",
"val_cmt": "HTTP/1.1"
},
"status_code": {
"fp": "20",
"val_cmt": "400"
},
"http_reason": {
"fp": "958a",
"val_cmt": "Bad Request"
},
"sl_reversed_db": {
"http_version": "HTTP/1.1",
"status_code": [
400,
422,
405,
401
],
"http_reason": "Bad Request"
}
},
"cont_len_hdr": {
"fp": "22",
"name": "Content-Length",
"value": ">1",
"cmt": "content-length/transfer-encoding:chunked header is present with either of the size values: [0,1,>1]"
},
"cnx": {
"ka": false,
"c": true
}
},
"p6f": {
"type": "get_accept_encoding_full",
"fp": "02",
"cont_enc_hdr": {
"value": "br",
"empty_value": false,
"total_plus": 0
}
},
"p6l": {
"type": "get_accept_encoding_less",
"fp": "02",
"cont_enc_hdr": {
"value": "br",
"empty_value": false,
"total_plus": 0
}
},
"p7a": {
"type": "options_allow_hdr",
"fp": "14254c5e72000000",
"status_line": {
"http_version": {
"fp": "14",
"val_cmt": "HTTP/1.1"
},
"status_code": {
"fp": "25",
"val_cmt": "405"
},
"http_reason": {
"fp": "4c5e",
"val_cmt": "Method Not Allowed"
},
"sl_reversed_db": {
"http_version": "HTTP/1.1",
"status_code": [
405,
403,
204,
418,
404
],
"http_reason": "Method Not Allowed"
}
},
"cont_len_hdr": {
"fp": "72",
"name": "Transfer-Encoding",
"value": ">1",
"cmt": "content-length/transfer-encoding:chunked header is present with either of the size values: [0,1,>1]"
},
"allow_hdr": {
"fp": "000000",
"cmt": "this header is not used"
},
"cnx": {
"ka": true,
"c": false
}
}
}
Observez que le tableau "status_code" contient plusieurs codes d'état HTTP. Cela se produit car différents serveurs peuvent utiliser la même phrase de raison pour différents codes d'état, ce qui donne des hachages FNV-1a identiques.
L'option de comparaison "-C/--compare" compare deux empreintes verbosus et affiche les différences entre les composants principaux de chacune des sondes.
Par exemple, comparer les deux empreintes suivantes pour Google et YouTube :
HTTPBasma.exe --compare 01140a85e4001320958a22142494d62214254c5e2214254c5e22080014254c5e220000000000,01140a85e4011320958a22142494d67214254c5e2214254c5e22080014254c5e220000000000
Donne le résultat suivant :
< FPrnt-1 Vs. FPrnt-2 >
[ P1 ]
{Strict-Transport-Security}
sts header: 00 != 01
[ P2 ]
[ P3 ]
{Content-Length}
cl_name: 2 != 7
[ P4 ]
[ P5 ]
[ P6F ]
[ P6L ]
[ P7a ]
La sortie révèle des différences spécifiquement dans le composant de hachage de la sonde P1, où l'en-tête STS est présent dans la première empreinte et pas dans l'autre. De plus, l'encodage du "Content-Length" est différent entre les deux empreintes pour la sonde P3.
Netomize fournit des versions compilées Windows et Linux x64 du code public de ce dépôt. De plus, le fichier CSV des empreintes HTTP-Basma de 1 million de sites Majestic - jeu de données est inclus dans la première version.
Ouvert aux pull requests et aux issues. Les commentaires et suggestions sont grandement appréciés.