Tristemente, esta es aun una de mas efectivas de estas tecnicas:
playground~> telnet hpux.u-aizu.ac.jp
Trying 163.143.103.12 ...
Connected to hpux.u-aizu.ac.jp.
Escape character is '^]'.
HP-UX hpux B.10.01 A 9000/715 (ttyp2)
login:
¡No vale la pena pasar por todo el procedimiento de indentificación si la máquina anunciara despreocupadamente al mundo exactamente que es lo que esta corriendo! Tristemente, muchos vendedores envian sistemas actuales con este tipo de letreros y muchos administradores no los quitan. Sólo porque hay otras maneras de averiguar que SO se esta corriendo, no quiere decir que vamos a anunciar nuestro SO y arquitectura a todo tarugo que trate de conectarse.
El problema con depender de esta técnica es que un numero creciente de gente está quitando los letreros, muchos sistemas no dan mucha información, y es trivial que alguien "mienta" en sus letreros.
Aun si quitas los banners, muchas aplicaciones felizmente regalaran este tipo de información cuando se les pregunte. Por ejemplo veamos a un servidor FTP:
payfonez> telnet ftp.netscape.com 21
Trying 207.200.74.26 ...
Connected to ftp.netscape.com.
Escape character is '^]'.
220 ftp29 FTP server (UNIX(r) System V Release 4.0) ready.
SYST
215 UNIX Type: L8 Version: SUNOS
Primero nos dá detalles del sistema en su letrero por omision. Despues si le damos el comando 'SYST', felizmente nos regresa aun mas información.
Si soporta FTP anonimo, muchas veces podemos bajar /bin/ls u otros binarios y determinar para que arquitectura fueron construidos.
Muchas otras aplicaciones tambien dan información gratis. Toma los servidores web por ejemplo:
playground> echo 'GET / HTTP/1.0\n' | nc hotbot.com 80 | egrep '^Server:'
Server: Microsoft-IIS/4.0
playground>
Otras tecnicas clásicas incluyen registros de información del anfitrión DNS (raramente efectivos) e ingenieria social. Si la maquina está escuchando 161/udp (snmp), casi se te garantiza muchísima información detallada usando 'snmpwalk' de la distribucion de herramientas de CMU SNMP y el nombre comunitario 'public'.
Nmap no es el primer programa de reconocimiento de SO que usa identificacion de TCP/IP. El spoofer para IRC sirc de Johan ha incluido tecnicas de identificacion muy primitivas desde la version 3 (o anteriores). Intenta colocar un anfitrion en las classes "Linux", "4.4BSD", "Win95", o "Desconocido" usando una cuantas pruebas simples de banderas de TCP.
Otro programa asi es checkos.
Las tecnicas de identificacion son exactamente las mismas que las de SIRC, y aun el codigo es identico en muchos lugares. Checkos ya estaba disponible privadamente por mucho tiempo antes de su puesta al publico, asi que no se sabe quién copió código a quién. Pero ninguno parece darle crédito al otro. Algo que checkos añade, es el chequeo del letrero de telnet, que es útil, pero tiene los problemas descritos con anterioridad.
Su1d tambien escribio un programa para checar SO's. El suyo se llama SS y a partir de la version 3.11 puede identificar 12 diferentes tipos de SO's.
Despues, está queso. Este programa es el mas nuevo y es una gran salto hacia delante sobre los otros programas. No solo introducen un par de pruebas novedosas, sino que fueron los primeros (que yo he visto) en mover las "huellas" fuera de el codigo. En su lugar, queso pone la información sobre las pruebas a los OS en un archivo de configuracion, que obviamente es mejor para incrementar y hace que poner otro SO sea tan facil como agregar unas cuantas lineas a un archivo de "huellas" .
Un problema con todos los programas descritos arriba es que estan muy limitados en el numero de pruebas de identificacion que limita la granularidad de las respuestas. No sirven si queremos saber mas que solo 'esta máquina es OpenBSD, FreeBSD, NetBSD', si queremos saber exactamente cuál de esas és, así como una idea de el numero de versión de el programa. De éste modo, sería preferible ver 'Solaris 2.6' que simplemente 'Solaris'.
Para obtener esta granularidad en las respuestas se trabajó en un numero de tecnicas de identificación que se describen en la siguiente sección.
Hay muchas, muchas técnicas que pueden ser usadas para identificar pilas TCP/IP. Básicamente, solo buscas cosas que difieran entre los sistemas operativos y escribes una prueba para la diferéncia. Si combinas suficientes pruebas, puedes aislar el SO con gran exactitud. Por ejemplo nmap puede distinguir confiablemente Solaris 2.4 vs. Solaris 2.5-2.51 vs Solaris 2.6. También puede identificar el kernel de Linux 2.0.30 del 2.0.31-34 o 2.0.35.
Aquí hay algunas técnicas:
La prueba FIN -- Aquí mandamos un paquete FIN (o cualquier paquete sin una bandera ACK o SYN) a un puerto abierto y esperamos una respuesta. El comportamiento correcto del RFC793 es no responder, pero muchas implantaciones incorrectas como MS Windows, BSDI, CISCO, HP/UX, MVS, e IRIX envian un RESET de regreso. Muchas de las herramientas actuales utilizan esta técnica.
La prueba de bandera MANIACA -- Queso es el primer escaner en utilizar esta prueba inteligente. La idea es poner una "bandera" TCP (64 o 128) en el encabezado TCP de un paquete SYN.
Linux antes de 2.0.35 mantienen la bandera puesta en su respuesta. No he encontrado ningun otro SO que tenga este defecto. Sin embargo, algunos sistemas operativos parecen cancelar la conexion cuando reciben un paquete SYN+MANIACA. Este comportamiento podria ser útil para identificarlos.
Probar TCP ISN -- La idea aquí es encontrar patrones en los numeros de secuéncia inicial seleccionados por las implantaciones de TCP al responder a solicitudes de conexion. Esto puede ser categorizado en muchos grupos como el tradicional 64K (muchos UNIX viejos), incrementos aleatorios (nuevas versiones de Solaris, IRIX, FreeBSD, Digital UNIX, Cray, y muchas otras), "Aleatoriedad" verdadera (Linux 2.0.*, OpenVMS, AIX mas nuevos, etc). Windows (y unas cuantas mas) usan un modelo "dependiente del tiempo" donde el ISN se incrementa por una pequeña cantidad estatica cada periodo de tiempo. Sin necesidad de decirlo, esto se vence tan fácilmente como el viejo comportamiento de 64K. Claro que la técnica mas débil es la "constante". Las máquinas SIEMPRE usan exactamente el mismo ISN. :). He visto esto en algunos hubs 3com (usan 0x803) y en impresoras Apple LaserWriter (usan 0xC7001). Tambien puedes subdividir grupos tales como incremento aleatorio por varianzas computacionales, maximos comunes divisores, y otras funciones en el conjunto números de secuéncia y las diferencias entre los números. Debe notarse que la generación de ISN tiene implicaciones de seguridad importantes. Nmap es el primer programa que usa ésto para identificacion de SO.
Bit de No-fragmentacion -- Muchos sistemas operativos estan empezando a poner el bit "no-fragmentacion" de IP en algunos paquetes que manda. Ésto da varios beneficios de rendimiento (aunque tambien puede se molesto, por esto las exploraciones de fragmentación de nmap no funcionan desde cajas Solaris). En cualquier caso, no todos los SO's hacen esto y algunos lo hacen en diferentes casos, asi que poniendo atención a este bit podemos obtener aún mas información sobre el SO objetivo.
Ventana Inicial TCP -- Ésto solo requiere mirar el tamaño de la ventana de los paquetes devueltos. Escaners mas viejos simplemente utilizan en una ventana no-zero un paquete RST para querer decir "derivado de BSD 4.4". Escaners mas nuevos como queso y nmap dan seguimiento a la ventana exacta, ya que es en realidad bastante constante segun el tipo de SO. De hecho esta prueba nos da mucha información, ya que algunos sistemas operativos pueden ser identificados de manera única por la ventana en sí (por ejemplo, AIX es el único SO que usa 0x3F25). En su pila TCP "completamente re-escrita" para NT5, Microsoft usa 0x402E. Interesantemente, ese es exactamente el numero usado por OpenBSD y FreeBSD.
Valor ACK -- A pesar de que podría pensarse que ésto sería completamente estándar, en algunos casos las implantaciones difieren en el valor que usan para el campo ACK. Por ejemplo, digamos que mandas un FIN|PSH|URG a un puerto TCP cerrado. La mayor parte de las implementaciones pondrán el ACK igual que tu numero de sequéncia inicial, pero Windows y algunas impresoras estupidas te mandaran tu secuéncia + 1. Si mandas un SYN|FIN|URG|PSH a un puerto abierto, Windows es muy inconsistente. Algunas veces regresa tu secuéncia, otras veces manda s++, y otras veces regresa un valor aparentemente aleatorio. Uno tiene que preguntarse que tipo de código está escribiendo MS que cambia su parecer de esta manera.
Control de Error de Mensaje ICMP -- Algunos sistemas operativos (inteligentes) siguen la sugerencia RFC 1812 de limitar la cantidad en que diferentes mensjaes de error son mandados. Por Ejemplo, el kernel de Linux (en net/ipv4/icmp.h) limita la generacion de mensajes de destino inalcanzable a 80 en 4 segundos, con 1/4 de segundo de castigo si se sobrepasa ese límite. Una manera de probar esto es mandar muchos paquetes a algún puerto UDP alto seleccionado al azar y contar el número de inalcanzables recibidos. nmap no lo integra para identificar el SO (excepto para usarlo con escaneo de puertos UDP). Esta prueba haría la detección de SO un poco mas lenta ya que se necesita mandar un montón de paquetes y esperar a que regresen. Y tambien tomar en cuenta la posibilidad de que los paquetes sean eliminados por la red.
Referenciacion de Mensaje ICMP -- Los RFCs especifican que los mensajes de error ICMP hacen referencia a una pequeña cantidad de un mensaje ICMP que provoca errores variados. Para un mensaje de puerto inalcanzable, casi todas las implementaciones mandan solo el encabezado IP requerido + 8 bytes de regreso. Sin embargo, Solaris devuelve un poco mas y Linux regresa aún mas. La belleza de ésto es que permite a nmap identificar a máquinas Linux y Solaris aun cuando no tengan ningun puerto escuchando.
Eco de Integridad de Mensajes de Error ICMP -- Como se ha mencionado antes, las máquinas tienen que regresar parte de tu mensaje original junto con un error de puerto inalcanzable. Y otras máquinas tienden a usar tus encabezados como 'borrador' durante su procesamiento inicial, asi que están un tanto alterados cuando te los devuelven. Por ejemplo, AIX y BSDI retornan un campo 'longitud total' de IP que es 20 bytes mayor. Algunos BSDI, FreeBSD, OpenBSD, ULTRIX, y VAXen desmadran el ID del IP que les mandaste. Mientras la suma de control va a cambiar debido que se cambia el TTL de todas formas, hay algunas máquinas (AIX, FreeBSD, etc.) que retornan una suma de control inconsistente o de 0. Lo mismo sucede con el suma de control UDP. Al final, nmap hace nueve diferentes pruebas de errores ICMP para "oler" diferencias sutiles como éstas.
Tipo de Servicio -- Para los mensajes de inalcanzable del puerto ICMP cambia el valor del tipo de servicio (TOS) en el paquete que retornan. Casi todas las implantaciones usan 0 para este error ICMP, aunque Linux usa 0xC0. Esto no indica uno de los valores TOS estandar, pero en vez de eso, es parte del campo de precedencia (AFAIK) que no es usado.
Manejo de Fragmentación -- Esto se aprovecha del hecho de que diferentes implantaciones seguido manejan fragmentos IP con superposición de manera diferente. Algunos sobreescribirán las viejas porciones con las nuevas, y en otros casos las cosas viejas tiene precedéncia. Hay muchas pruebas diferentes que se pueden usar para determinar como el paquete fue reensamblado. Para mas información sobre fragmentos superpuestos, mirar IDS (www.secnet.com).
Opciones TCP -- Esto es una verdadera mina de oro en términos de fugas de información. La belleza de estas opciones es que:
1) son generalmente opcionales, asi que no todas las máquinas las implantan. 2) Sabes si una maquina las implanta mandando una solicitud con una opción definida. El objetivo generalmente muestra que soporta la opción poniéndola también en la respuesta. 3) Puedes poner muchas opciones en un paquete para probar todo al mismo tiempo.
Nmap manda estas opciones en casi todos los paquetes de prueba: Window Scale=10; NOP; Max Segment Size = 265; Timestamp; End of Ops;
Cuando obtienes una respuesta, miras que opciones te regresaron y por lo tanto son soportadas. Algunos sistemas operativos como FreeBSD recientes soportan todas las anteriores, mientras otras, como Linux 2.0.X soportan muy pocas. Los kernels Linux 2.1.x mas recientes soportan todas la anteriores. Por otro lado, son mas vulnerables a prediccion de secuéncia TCP. Aun si varios sistemas operativos soportan las mismas opciones, se pueden distinguir algunas veces por los valores de las opciones. Por ejemplo, si mandas un valor MSS pequeño a un Linux, generalmente te hará un eco con ese MSS de regreso. Otras máquinas te daran un valor diferente. Y aun si obtienes el mismo conjunto de opciones soportadas Y los mismos valores, puedes diferenciar por el órden en que las opciones son devueltas, y dónde se pone relleno. Por ejemplo Solaris regresa 'NNTNWME' que significa:
<no op><no op><timestamp><no op><window scale><echoed MSS>
Mientras que Linux 2.1.122 regresa MENNTNW. Mismas opciones, mismos valores, pero diferente órden.
Cronología de Explotación -- Aun con todas la pruebas anteriores, nmap es incapaz de distinguir entre las pilas TCP de Win95, WinNT, o Win98. Esto es algo sorprendente, especialmente ya que Win98 salió como 4 años despues que Win95. Pensarías que se habrían preocupado en mejora la pila de alguna manera (como soportar mas opciones TCP) y de esta manera podríamos detectar el cambio y distinguir entre los sistemas operativos. Desafortunadamente este no es el caso. La pila NT es aparentemente la misma mierda de pila que pusieron en el '95. Y no se molestaron en actualizarla para el '98.
Pero hay una solución. Puedes simplemente empezar con antiguos ataques para Windows DOS (Ping of Death, WinNuke, etc) y despues cambiar un poco mas arriba a ataques como Teardrop y Land. Después de cada ataque, hacer un ping para ver si se colgaron. Cuando finalmente se cuelgan, ya habrás deducido la la versión que estan corriendo, e incluso hasta de paquete o parche.
Esta función no está en nmap, aunque podría ser útil.
Resistencia a Inundación de SYN -- Algunos sistemas operativos dejan de aceptar nuevas conexiones si les mandas demasiados paquetes SYN falsificados (falsificar los paquetes impide que tu kernel corte las conexiones). Muchos sistemas operativos pueden solo manejar 8 paquetes. Kernels recientes de Linux (entre otros sistemas operativos) permiten varios métodos, como cookies SYN para prevenir que ésto se convierta en un problema serio. Asi que puedes aprender algo de tu SO objetivo al mandarle 8 paquetes de una fuentes falsificada a un puerto abierto y despues probando si puedes establecer una conexión a ese puerto tu mismo. Esto no fue implantado el nmap ya que algunas personas se enfadan cuando los inundas con SYN's. Aun explicando que solo tratabas de determinar que tipo de SO estan corriendo no ayudara a calmarlos.
nmap es portable entre Linux, *BSD, y Solaris 2.51 y 2.6, y algunos otros sistemas operativos.
La nueva version de nmap lee un archivo lleno con los esqueletos de las huellas que siguen una gramatica simple. Aqui hay un ejemplo:
Huella IRIX 6.2 - 6.4 # Gracias a Lamont Granquist
FingerPrint IRIX 6.2 - 6.4 # Thanks to Lamont Granquist
TSeq(Class=i800)
T1(DF=N%W=C000|EF2A%ACK=S++%Flags=AS%Ops=MNWNNT)
T2(Resp=Y%DF=N%W=0%ACK=S%Flags=AR%Ops=)
T3(Resp=Y%DF=N%W=C000|EF2A%ACK=O%Flags=A%Ops=NNT)
T4(DF=N%W=0%ACK=O%Flags=R%Ops=)
T5(DF=N%W=0%ACK=S++%Flags=AR%Ops=)
T6(DF=N%W=0%ACK=O%Flags=R%Ops=)
T7(DF=N%W=0%ACK=S%Flags=AR%Ops=)
PU(DF=N%TOS=0%IPLEN=38%RIPTL=148%RID=E%RIPCK=E%UCK=E%ULEN=134%DAT=E)
Miremos la primera linea:
Huella IRIX 6.2 - 6.3 # Gracias a Lamont Granquist: Esto dice simplemente que la huella cubre las versiones 6.2 y 6.3 de IRIX y el comentario dice que Lamont Grandquist amablemente mandó la direccion IP o la huella de las máquinas IRIX probadas.
TSeq(Class=i800): Esto significa que un muestreo ISN lo puso en la clase "i800". Esto significa que cada nueva secuéncia de numeros es un multiplo de 800 mayor que el ultimo.
T1(DF=N%W=C000|EF2A%ACK=S++%Flags=AS%Ops=MNWNNT): La prueba se llama T1 (por test1 en Inglés). En esta prueba mandamos un paquete SYN con muchas opciones TCP a un puerto abierto. DF=N significa que el bit "no fragmentación" de la respuesta debe estar puesto. W=C000|EF2A quiere decir que el anuncio de ventana que recibimos deber ser 0xC000 o EF2A. ACK=S++ quiere decir que el reconocimiento que recibimos debe ser nuestra secuéncia inicial mas 1. Flags = AS quiere decir que las banderas ACK y SYN fueron mandadas en la respuesta. Ops=MNWNNT quiere decir que las opciones en la respuesta deben ser (en este orden):
<MSS (not echoed)><NOP><Window scale><NOP><NOP><Timestamp>
T2(Resp=Y%DF=N%W=0%ACK=S%Flags=AR%Ops=): La prueba 2 involucra a un NULL con las mismas opciones a un puerto abierto. Resp=Y significa que debemos obtener una respuesta. Ops= significa que no debe haber ningunas opciones incluidas en el paquete respuesta. Si quitaramos '%Ops=' completamente, entonces cualquier opcion mandada correspondería.
T3(Resp=Y%DF=N%W=400%ACK=S++%Flags=AS%Ops=M): La prueba 3 es un SYN|FIN|URG|PSH con opciones a un puerto abierto.
T4(DF=N%W=0%ACK=O%Flags=R%Ops=): Ésta es un ACK a un puerto abierto. Notar que no tenemos un Resp= aquí. Ésto significa que la falta de respuesta (como el paquete que haya sido eliminado por la red o un firewall malévolo) no descalificara correspondecia mientras todas las otras pruebas correspondan. Hacemos ésto porque virtualmente cualquier SO mandará una respuesta, asi que la falta de ésta es generalmente un atributo de las condiciones de la red y no de el SO en sí. Ponemos la etiqueta de Resp en las pruebas 2 y 3 porque algunos sistemas operativos si los elimina sin responder.
T5(DF=N%W=0%ACK=S++%Flags=AR%Ops=),
T6(DF=N%W=0%ACK=O%Flags=R%Ops=) y
T7(DF=N%W=0%ACK=S%Flags=AR%Ops=): Éstas pruebas son SYN, ACK, y FIN|PSH|URG, respectivamente, a un puerto cerrado. Las mismas opciones estan puestas, como siempre. Claro que esto es probablemente obvio dado los nombres descriptivos 'T5', 'T6' y 'T7'.
PU(DF=N%TOS=0%IPLEN=38%RIPTL=148%RID=E%RIPCK=E%UCK=E%ULEN=134%DAT=E): Ésta es la prueba de mensaje de 'puerto inalcanzable'. Ya deberías reconocer el DF=N a estas alturas. TOS=0 significa que el campo de tipo de servicio IP era 0. Los siguientes dos campos dan los valores (hex) del campo de longitud total de IP del encabezado IP del mensaje y la longitud total dada en el encabezado IP que nos devolvieron por eco a nosotros. RID=E significa que el valor RID que obtuvimos en la copia de nuestro paquete UDP original se esperaba (por ejemplo el mismo que mandamos). RIPCK=F significa que no modificaron la suma de control (si lo hicieron, diria RIPCK=F). UCK=E significa que la suma de control UDP tambien está correcta. Despues viene la longitud UDP que era 0x134 y DAT=E significa que hicieron un eco de nuestro UDP correctamente. Ya que la mayoría de las implantaciones (incluyendo ésta) no envían ninguno de nuestros datos UDP de regreso, obtienen DAT=E por omisión.
Fuentes: