En SSL / TLS , los mensajes se envían como parte de los registros . Lo que se debe esperar es que el cliente envíe primero un mensaje ClientHello
que está contenido en uno o varios registros.
El formato de grabación es:
record type: 1 byte (0x16 for "records contains some handshake message data")
protocol version: 2 bytes (0x03 0x00 for SSL 3.0, 0x03 0x01 for TLS 1.0, and so on)
record length: 2 bytes (big endian)
then the record data...
Para el primer registro (de cliente a servidor), el cliente primero enviará un mensaje ClientHello
que es un tipo de mensaje de intercambio, por lo tanto, se encapsula en un registro como se muestra arriba (el primer byte del registro será 0x16 ). Teóricamente , el cliente puede enviar el ClientHello
dividido en varios registros, y puede comenzar con uno o varios registros vacíos, pero esto no es muy probable. El mensaje ClientHello
comienza con su propio encabezado de cuatro bytes, con un byte para el tipo de mensaje (0x01 para ClientHello
), luego la longitud del mensaje sobre tres bytes (nuevamente, big-endian).
Una vez que el cliente haya enviado su ClientHello
, espera una respuesta del servidor, por lo que ClientHello
estará solo en su registro.
Por lo que podría esperar una carga útil que comience con los siguientes 9 bytes:
0x16 0x03 X Y Z 0x01 A B C
con:
X será 0, 1, 2, 3 ... o más , dependiendo de la versión de protocolo utilizada por el cliente para este primer mensaje. Actualmente , las versiones de SSL / TLS definidas son SSL 3.0 , TLS 1.0 , TLS 1.1 y TLS 1.2 . Otras versiones pueden ser definidas en el futuro. Ellos probablemente usarán el esquema de numeración 3. X , por lo que puede esperar que el segundo byte de encabezado permanezca en 0x03, pero no debe limitar arbitrariamente el tercer byte.
Y Z es la codificación de la longitud del registro; A B C es la codificación de la longitud del mensaje ClientHello
. Como el mensaje ClientHello
comienza con un encabezado de 4 bytes (no incluido en su longitud) y se supone que está solo en su registro, debe tener: A = 0 y 256 * X + Y = 256 * B + C + 4 .
Si ve 9 bytes, que verifican estas condiciones, es probable que esto sea un ClientHello
de un cliente SSL.
Algunos clientes SSL no muy recientes también pueden admitir una versión de protocolo más antigua, llamada SSL 2.0. Estos clientes emitirán un ClientHello
que sigue las reglas de SSL 2.0, donde los mensajes y registros se fusionan de alguna manera. Ese mensaje SSL 2.0 ClientHello
indicará que el cliente también conoce SSL 3.0 o más reciente, pero no comenzará con la secuencia de 9 bytes explicada anteriormente.
La estructura de
SSL 2.0 ClientHello
se explica en apéndice E.2 o RFC 5246 . Aunque estos clientes son raros (hay un RFC sobre la prohibición total de la compatibilidad con SSL 2.0), todavía hay muchos implementados ahí fuera.
Tu código tiene algunos problemas:
- No detecta un mensaje SSL 2.0
ClientHello
.
- Comprueba que el tercer byte del encabezado ( X en mi descripción anterior) es igual a 0, 1 o 2, lo que descarta TLS 1.2. Esto es demasiado restrictivo.
- Supone que todo
ClientHello
estará en un solo registro (lo que es una suposición razonable) y que este ClientHello
se codificará en un solo paquete (que es una suposición mucho menos razonable).
- No intenta ver la longitud en el mensaje de saludo y lo corrobora con la longitud del registro.
Correspondientemente, eludir la detección será fácil (al usar un SSL 2.0 ClientHello
, al usar un registro etiquetado con la versión TLS 1.2, al hacer un gran mensaje ClientHello
que no cabe en un solo paquete ... los métodos son numerosos); y algunos clientes implementados existentes no serán detectados: no solo uno puede evitar la detección a propósito , sino que también es posible sin querer .