
En el ámbito de la ciberseguridad, identificar y caracterizar con precisión los servidores web es crucial para la detección de amenazas, la evaluación de vulnerabilidades y el mapeo de redes. Presentamos HTTP-Basma, un novedoso algoritmo de fingerprinting activo que revela perfiles únicos de servidores mediante un enfoque multicapa.
HTTP-Basma está disponible en https://httpbasma.netomize.ca/
En el ámbito de la ciberseguridad, identificar y caracterizar con precisión los servidores web es crucial para la detección de amenazas, la evaluación de vulnerabilidades y el mapeo de redes. Presentamos HTTP-Basma, un novedoso algoritmo de fingerprinting activo que revela perfiles únicos de servidores mediante un enfoque multicapa, abordando así este desafío.
Características principales: Solicitudes elaboradas, respuestas reveladoras: HTTP-Basma envía 8 sondas HTTP meticulosamente diseñadas que provocan respuestas distintivas que reflejan las configuraciones del servidor. Doble hash para versatilidad. El algoritmo genera dos hashes:
Agrupación y caza: Estos hashes permiten la agrupación de servidores, la identificación de servidores únicos y similares, y la persecución de actores maliciosos con mayor confianza.
Diseño modular para la expansión: La arquitectura del algoritmo fomenta la adición de nuevas variantes de hash, incentivando la colaboración y la adaptabilidad.
En este documento, primero revisamos trabajos existentes notables sobre fingerprinting HTTP y luego exploramos la funcionalidad, el diseño, la arquitectura y los resultados del algoritmo. Además, mostraremos hallazgos convincentes del análisis de los 1 millón de sitios web principales de Majestic, incluida la identificación y agrupación de servidores HTTP de C&C para varias familias de malware.
La idea central del algoritmo de HTTP-Basma consiste en enviar 8 solicitudes HTTP especialmente diseñadas con requisitos variables para provocar diferentes respuestas del servidor. Una vez obtenida la respuesta del servidor, la línea de estado HTTP se disecciona quirúrgicamente para extraer todos sus elementos y se codifica de forma óptima. Además, también se comprueba la codificación de ciertos encabezados seleccionados de la respuesta del servidor.
Las solicitudes que envía son de los siguientes tipos:
Tras cada solicitud, se analiza la respuesta del servidor para extraer encabezados específicos y sus valores. Estos datos extraídos se someten a un procesamiento adicional, que incluye disección y codificación, para generar una huella digital reversible.
Los detalles técnicos completos sobre cómo funciona el algoritmo se encuentran en el documento adjunto.
Esta filosofía de diseño modular trata la huella de cada solicitud como un bloque de construcción, lo que permite una refactorización elegante, con la posibilidad de añadir o restar la huella de cualquier solicitud.
Ejemplo de huellas digitales:
- 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 es una herramienta en C++ que desarrollé para demostrar la practicidad y viabilidad de este algoritmo. Aprovecha la librería de Chilkat para todas las interacciones de sockets HTTP y utiliza otras clases de soporte dentro de la librería. Además, la herramienta incluye una función demangler que puede diseccionar y revertir el hash difuso verbosus, generando un objeto JSON completo, y una función comparadora que muestra las diferencias entre dos huellas verbosus.
Ten en cuenta que parte de la salida de la herramienta podría usar números de sonda ligeramente diferentes, pero el orden subyacente se mantiene coherente: 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
Al consultar un dominio/IP determinado, la respuesta puede guardarse en un archivo CSV o JSON con una gran cantidad de información sobre los encabezados de respuesta del servidor y la huella única de cada sonda.
Por ejemplo, para obtener la huella del servidor https://google.com y guardar los resultados en un archivo JSON y CSV, guardando también los encabezados de respuesta HTTP de cada sonda:
HTTPBasma.exe -d https://google.com --json --csv --saveh
En la carpeta Output, encontrarás el archivo CSV google_hb_results_2026-05-19_08-35-38_am.csv y el archivo JSON google_hb_results_2026-05-19_08-35-38_am.json.
La función demangler de la herramienta "-i/--demangle_json" toma una huella verbosus y reconstruye los atributos de cada sonda, generando un objeto JSON completo. En particular, al intentar revertir los hashes FNV-1a, el demangler utiliza dos bases de datos locales: options.csv para los métodos HTTP permitidos y status_line_db.csv para las frases de razón de la línea de estado. Si falta alguno de estos archivos de base de datos, la característica de reversión de hash correspondiente se desactiva automáticamente. Estas bases de datos se compilaron a partir de un análisis de los 1 millón de sitios web principales de Majestic.
El demangling de la huella verbosus, para el dominio 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
}
}
}
Observa que el campo "status_code" contiene múltiples códigos de estado HTTP. Esto ocurre porque diferentes servidores podrían usar la misma frase de razón para distintos códigos de estado, lo que da como resultado hashes FNV-1a idénticos.
La opción comparador "-C/--compare" compara dos huellas verbosus e imprime las diferencias entre los componentes principales de cada una de las sondas.
Por ejemplo, al comparar las siguientes dos huellas de Google y YouTube:
HTTPBasma.exe --compare 01140a85e4001320958a22142494d62214254c5e2214254c5e22080014254c5e220000000000,01140a85e4011320958a22142494d67214254c5e2214254c5e22080014254c5e220000000000
Esto produce la siguiente salida:
< 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 salida revela diferencias específicamente en el componente de hash de la sonda P1, donde el encabezado STS está presente en la primera huella y no en la otra. Además, la codificación de "Content-Length" es diferente entre las dos huellas para la sonda P3.
Netomize ofrece versiones compiladas para Windows y Linux x64 del código público de este repositorio. Además, el archivo CSV de huellas HTTP-Basma de 1 millón de sitios Majestic - conjunto de datos se incluye en la primera versión.
Abierto a pull requests e issues. Los comentarios y sugerencias son muy apreciados.