-----------------------------------------------------
Continuación
-----------------------------------------------------
II Analisis basado en la pila TCP/IP
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Antes de pasar a enumerar los programas que han hecho posible
el reconocimiento del sistema operativo de un host de forma remota me
parece logico explicar, a grandes rasgos, cual es su funcionamiento,
sin entrar de momento en particularidades.
Dichos programas basan su funcionamiento en analizar las
diferentes respuestas que ofrecen distintos sistemas ante ciertos
envios (he aqui las singularidades y la variedad de metodos). Por
tanto, dichas respuestas, que son comunmente conocidas como TCP/IP
fingerprints, son las que permiten distinguir un sistema operativo de
otro. Muchas veces, recurren dichos programas a distintos tipos de
envios ya que, en muchas ocasiones, las diferencias en la pila TCP/IP
de un sistema operativo a otro no son muy marcadas y ante ciertos
envios actuan de igual forma, diferenciandose, a veces, solo en uno o
incluso no habiendo diferencia (como en el caso de Windows 95/98/NT,
en los que increiblemente no se observa un comportamiento diferente en
sus pilas TCP/IP; unicamente probando nukes contra dichos hosts y
viendo si se caen o no, para asi distinguir por ejemplo entre un 95 y
un 98 (ej. WinNuke)).
Entre los programas disponibles que utilizan dicha tecnica de
fingerprinting destacan:
-spoofer para IRC sirc (Johan)
-checkos (shok)
-nmap (fyodor)
-nsat (mixter)
-p0f (Michal Zalewski)
-SS (Su1d)
-queso (savage)
Ya entrando mas a fondo en el funcionamiento a mas bajo nivel
de dichos programas encontramos cierta diferencia entre ellos, ya que
mientras unos usan un fichero externo con fingerprints de diferentes
sistemas tipo, como el queso, otros incluyen en el codigo dicha
comparacion, como checkos por ejemplo.
En checkos encontramos:
...
if ((tcp.hrc & CF_SYN) && (tcp.hrc & CF_FIN)) {
type=OS_LINUX;
done=1;
}
...
if ((tcp.hrc & CF_ACK) && (tcp.hrc & CF_RST)) {
if (flags & OSD_WIN95WAIT) {
done=1;
type=OS_WIN95;
}
En ss encontramos:
/* fragmento codigo de ss de Remote OS
Detection via TCP/IP Fingerprinting de
Fyodor */
...
if ((flagsfour & TH_RST) && (flagsfour & TH_ACK) && (winfour == 0) &&
(flagsthree & TH_ACK))
reportos(argv[2],argv[3],"Livingston Portmaster ComOS");
...
Mientras que en queso encontramos un fichero de configuracion
en el que se distingue por ejemplo:
$ cat /etc/queso.conf
...
* AS/400 OS/400 V4R2 (by rodneybrown@pmsc.com)
0 1 1 1 SA
1 0 1 0 R
2 0 1 0 RA
3 0 1 0 R
4 1 1 1 SA
5 0 1 0 RA
6 1 1 1 SA
...
Se observa, pues, que savage ha implementado de forma bastante
mas inteligente dicha idea. Este metodo ha sido heredado por fyodor
para su nmap, y por ejemplo, en ciertas versiones de nmap encontramos:
$ cat /usr/local/lib/nmap/nmap-os-fingerprints
...
# Thanks to Juan Cespedes <cespedes@lander.es>
FingerPrint AGE Logic, Inc. IBM XStation
TSeq(Class=64K)
T1(DF=N%W=2000%ACK=S++%Flags=AS%Ops=M)
T2(Resp=N)
T3(Resp=Y%DF=N%W=2000%ACK=O%Flags=A%Ops=)
T4(DF=N%W=2000%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=F%RIPCK=0%UCK=E%ULEN=134%DAT=E)
...
Y tambien ha sido usado por mixter en su NSAT, destacando la
distincion que hace entre diferentes configuraciones de windows:
$ cat /usr/local/bin/nsat.os
...
Windows (Firewall-1)
1 1 1 0 1 18
1 0 1 0 0 4
1 0 1 0 1 21
1 0 1 0 1 21
1 1 1 0 1 18
1 0 1 0 1 28
0 0 0 0 0 0
...
En lo que se refiere al tipo de tecnicas usadas para
diferenciar unos OSs se debe puntualizar que en realidad, estas
pruebas se combinan, para asi conseguir aislar cada sistema
operativo. Un muy buen programa para hacer este tipo de pruebas es el
hping2 (antirez@invece.org, http://www.kyuzz.org/antirez/hping2.html)
o sing (aandres@mfom.es, http://sourceforge.net/projects/sing/)
combinandolo con el analisis mediante tcpdump o ethereal (un magnifico
frontend), ya que aunque puedes realizar tu propio codigo (en C, por
ejemplo) esta claro que esto conlleva unos conocimientos de unix
network programing bastante importantes, asi que en este paper
analizare los resultados obtenidos con hping2 y no presentare codes
especificos para cada prueba, además utilizare mi propia maquina para
dichas pruebas y no lo hare de forma remota para asi tener un mayor
control de los resultados. Los metodos que conozco son: (si conoces
otras tecnicas utilizadas para esto no dudes en decirmelo -
honoriak@mail.ru)
- TCP ISN: Cuando el host a analizar responde a solicitudes de
conexion, genera unos numeros en la secuencia inicial (ISN) que no
siempre se producen de la misma forma; esto, es aprovechado para
distinguir unos sistemas de otros. Estos ISNs pueden ser constantes
(hubs de 3com, etc.), 64K (UNIX antiguos), aleatorios (linux >2.0, AIX
modernos, OpenVMS), incremento en funcion del tiempo (windows), de
incremento aleatorio (freebsd, digital unix, cray, solaris
modernos...) siendo estos ultimos incrementos basados en diferentes
cosas como por ejemplo maximos comunes divisores.
Si enviamos varios paquetes, por ejemplo, de la forma:
$ hping2 localhost -p 80
default routing not present
HPING localhost (lo 127.0.0.1): NO FLAGS are set, 40 headers + 0 data
bytes
40 bytes from 127.0.0.1: flags=RA seq=0 ttl=255 id=5 win=0 rtt=0.4 ms
40 bytes from 127.0.0.1: flags=RA seq=1 ttl=255 id=6 win=0 rtt=24.9 ms
--- localhost hping statistic ---
2 packets tramitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.4/12.6/24.9 ms
Y ahora analizamos dichos paquetes por ejemplo con el tcpdump
(mas claro son los resultados que ofrece ethereal, pero para copiar
aqui es mas comoda la salida del tcpdump; solo copiare las respuestas,
no las peticiones)
...
14:12:47.774380 lo < honorato.2485 > honorato.www: . 7200421:72
00421(0) win 512
...
14:12:48.771779 lo < honorato.2486 > honorato.www: . 2002659674:200
2659674(0) win 512
...
Se observa, pues, una variacion en la seq inicial del paquete
TCP, en el primer paquete vemos 7200421 y en el segundo 2002659674
siendo en este caso completamente aleatorios ya que estoy trabajando
en:
$ uname -a
Linux honorato.com 2.2.16 #14 SMP Sat Jun 10 15:51:08 CEST 2000
i86 unknown
- Opciones de TCP: esta tecnica se basa en el diferenciar
sistemas operativos segun el numero de opciones TCP que admiten, los
valores de dichas opciones y el orden en que las opciones se nos
presentan. Esto, que yo sepa, solo es utilizado por Nmap (si sabes de
otros programas que lo usen, no dudes en decirmelo y modificare esto).
Fyodor en su nmap hace prueba las siguientes opciones:
Window Scale=10; NOP; Max Segment Size = 265; Timestamp; End of Ops;
El hping2 no implementa esta posibilidad (o eso creo) asi que
no lo he llevado a la practica. Siempre puedes analizar el codigo del
nmap que realiza esto y heredar dicha tecnica.
- FIN: Se basa en el envio a un puerto abierto del host a
estudio de un paquete FIN o cualquiera que no tenga un flag ACK o
SYN. Segun el RFC793 el host no tendria que responder pero algunos OSs
responden con un RESET como Windows, HP/UX, IRIX, MVS, BSDI, CISCO.
Para hacer una prueba practica usare el puerto 80, con apache
arrancado:
$ /usr/bin/httpd
$ hping2 localhost -p 80 -F
default routing not present
HPING localhost (lo 127.0.0.1): F set, 40 headers + 0 data bytes
--- localhost hping statistic ---
4 packets tramitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms
Se observa pues, como mi linux si que cumple el RFC793 y no responde a
dichos paquetes.
- ACK recibido: El valor de ACK que nos envia el servidor a
analizar cuando por ejemplo enviamos un SYN|FIN|URG|PSH a un puerto
abierto o un FIN|PSH|URG a un puerto cerrado puede variar respecto al
numero de secuencia inicial que envia este.
Para probar, inicialmente mandare un paquete normal a un
puerto cerrado, y se comprueba que el valor de ACK no cambia y despues
uno FIN|PSH|URG tambien a un puerto cerrado y se vera como cambia:
$ killall httpd
$ hping2 localhost -p 80
...
y en la salida del tcpdump se ve
15:59:37.442157 lo > honorato.1676 > honorato.www: . 1752870898:1752
870898(0) win 512
15:59:37.442157 lo < honorato.1676 > honorato.www: . 1752870898:1752
870898(0) win 512
15:59:37.442259 lo > honorato.www > honorato.1676: R 0:0(0) ack 1752
870898 win 0
vemos como 1752870898 se mantiene en el ack, pero en cambio:
$ hping2 localhost -p 80 -S -F -U -P
...
y en la salida del tcpdump ahora vemos
16:00:48.480252 lo > honorato.2669 > honorato.www: SFP 1376153753:13
76153753(0) win 512 urg 0
16:00:48.480252 lo < honorato.2669 > honorato.www: SFP 1376153753:13
76153753(0) win 512 urg 0
16:00:48.480334 lo > honorato.www > honorato.2669: R 0:0(0) ack 1376
153754 win 0
Se ve pues como ha cambiado el valor de seq respecto al de ack
de 1376153753 a 1376153754.
De la misma forma, haciendo dicha prueba para un puerto
abierto se puede ver que hay una variacion. En estas pruebas he usado
linux, pero de un sistema a otro esa variacion puede ser diferente (lo
que permite diferenciarlos, claro esta).
- Flag TCP (64/128) en el encabezado TCP de un paquete SYN:
Haciendo esto, por lo que yo he probado/leido unicamente el linux
2.0.35 mantiene dicha flag en la respuesta y el resto cancela la
conexion. Esto, de estudiarse a fondo, puede servir para diferenciar
OSs.
No he hecho una demostracion practica de dicho metodo, ya que
en este momento no tengo instalado el kernel 2.0.35, pero simplemente
se haria: hping2 localhost -p 80 -S y se analizarian los resultados
vertidos por el tcpdump.
- ICMP:
1) Esta tecnica se basaria en el control del numero de
mensajes de destination unreachable que envia un host por ejemplo al
mandar un gran numero de paquetes a un puerto UDP. En linux,
encontramos como limita dicha cantidad de mensajes, y por ejemplo:
$ cat /usr/src/linux/net/ipv4/icmp.c
...
* 4.3.2.8 (Rate Limiting)
* SHOULD be able to limit error message rate (OK)
* SHOULD allow setting of rate limits (OK, in the source)
...
Pero, esta tecnica es de dificil implementacion, ya que habria
que considerar la posibilidad de que los paquetes se perdiesen.
$ hping2 localhost --udp -i u[intervalo_en_microsegundos]
...
--- localhost hping statistic ---
*** packets tramitted, * packets received, ***% packet loss
round-trip min/avg/max = *.*/*.*/*.* ms
Y se analizaria si limita o no el numero de paquetes de ICMP
Port Unreachable. Pero, no hago la prueba con mi localhost ya que las
condiciones son completamente diferentes a las condiciones que te
encontrarias en internet. Aun asi, veo de dificil implementacion esta
tecnica por lo dicho anteriormente.
2) Basandose en los mensajes de error ICMP, y centrandose en
los mensajes que se refieren a que no se pudo alcanzar un puerto casi
todos los OSs mandan simplemente el encabezado ip y ocho bytes; pero,
tanto solaris como linux mandan una respuesta un poco mas larga siendo
este ultimo el que responde con mayor numero de bytes. Esto, claro
esta, puede ser utilizado para distinguir unos OSs de otros.
$ hping2 localhost --udp -p 21
y si analizamos uno de los paquetes ICMP de Destination
unreachable observamos:
Header length: 20 bytes
Protocol: ICMP (0x01)
Data (28 bytes)
Type: 3 (Destination unreachable)
Code: 3 (Port unreachable)
se observa pues como en sistemas linux ademas del encabezado
ip se retornan bastante mas de 8 bytes, 28 bytes.
3) Fijandose nuevamente en los mensajes de error ICMP debido a
que no se pudo alcanzar un puerto, se observa que todos los OSs a
excepcion de linux usa como valor de TOS (tipo de servicio) 0, pero
linux en cambio, usa 0xc0 siendo esto parte del AFAIK, el campo de
referencia, que no es usado.
$ hping2 localhost --udp -p 21
y en el tcpdump, por ejemplo, observamos la siguiente salida:
16:27:57.052282 lo > honorato > honorato: icmp: honorato udp port fs
p unreachable [tos 0xc0]
16:27:57.052282 lo < honorato > honorato: icmp: honorato udp port fs
p unreachable [tos 0xc0]
siendo el tos 0xc0 como he expuesto anteriormente, ya que se
trata de un linux, a diferencia de los demas sistemas operativos.
4) Basandose en los encabezados de los paquetes ICMP de error
vemos como diferentes OSs lo utilizan como 'scratch space'. Es decir,
lo modifican; y asi por ejemplo encontramos como freebsd, openbsd,
ultrix... cambian el ID de la IP del mensaje original en su respuesta,
bsdi aumenta en 20 bytes la longitud total del campo de IP... (y hay
mas diferencias, que estan por analizar, asi que ya sabes).
En mi linux, por ejemplo, el un paquete udp al puerto 0 es:
0000 00 00 08 00 45 00 00 1c a4 c8 00 00 40 11 d8 06 ....E... ....@...
0010 7f 00 00 01 7f 00 00 01 0a e5 00 00 00 08 f6 f6 ........ ........
y su el paquete ICMP de Destination unreachable es:
0000 00 00 08 00 45 c0 00 38 22 de 00 00 ff 01 9a 24 ....E..8 "......$
0010 7f 00 00 01 7f 00 00 01 03 03 fb 18 00 00 00 00 ........ ........
0020 45 00 00 1c a4 c8 00 00 40 11 d8 06 7f 00 00 01 E....... @.......
0030 7f 00 00 01 0a e5 00 00 00 08 f6 f6 ........ ....
En linux, el campo de la IP, no varia del paquete udp al icmp
de error a diferencia de otros SOs pero pasa de tener id: 0xa4c8 a
tener id: 0x22de. Este metodo no lo he estudiado a fondo y veo que
puede tener bastantes particularidades. Si quieres tener una vision
un poco mas completa del escaneo de puertos mediante metodos basados
en ICMP puedes leer ICMP usage in scanning o tambien llamado
Understanding some of the ICMP Protocol's Hazards de Ofir Arkin de
Sys-security Group en http://www.sys-security.com.
5) Esta tecnica solo puede ser usada, en plataformas
unix/linux/bsd y no en win* ya que win no responde a las queries que
seran usadas, que son de ICMP tipo 13 o tambien conocidas como ICMP
Timestamp Request.
En el caso del sistema operativo linux, que es el que poseo
podemos observar la siguiente prueba:
$ sing -vv -tstamp 127.0.0.1 ...
del que se obtendra un tiempo de respuesta de timestamp que
puede ser utilizado para diferenciar unos OSs de otros.
6) Esta tecnica se basa en el funcinamiento especifico de los
routers.
En particular, se basa en ICMP Router Solicitation (ICMP de
tipo 10). Cada router 'multicastea' cada cierto tiempo un anuncio de
ruta (ICMP de tipo 9) desde cada una de sus interfaces de 'multicast',
y de esta forma anuncia la direccion IP del interfaz.
Si vemos que el host remoto responde con ICMP de tipo 9 frente
a un ICMP de tipo 10, entonces nos encontramos ante un router. Pero,
los routers que tengan suprimida esta caracteristica no seran
detectados.
Las pruebas para este metodo las puedes realizar tanto con
hping2 como con sing (antiguo icmpush), pero el ultimo fue el primero
en implementarla, y asi encontramos:
$ sing -rts 127.0.0.1
...
$ hping2 -C 10 127.0.0.1
...
- Bit no fragmentado: esta tecnica se basa en que ciertos
sistemas operativos ponen un bit no fragmentado de IP en algunos de
los paquetes que envian. Pero lo que es cierto es que no todos lo
hacen, y de hacerlo no lo hacen de la misma forma; lo que puede ser
aprovechado para averiguar el OS.
en mi linux (del que ya he copiado un uname -a antes, para
saber el kernel que uso):
$ hping2 localhost
...
al analizar uno de los paquetes tcp mandados con ethereal se
comprueba que:
Flags: 0x04
.1.. = Don't Fragment: Set
..0. = More fragments: Not set
pero, tampoco he hecho un gran numero de pruebas para asegurar
que en algun caso y con cierto tipo de paquetes no se adjunte dicho
bit. Aun asi, hay OSs que nunca lo usan como SCO o OpenBSD.
- La ventana inicial de TCP: se basa en la comprobacion de las
dimensiones de la ventana de los paquetes que nos devuelve el host a
estudiar. El valor que toma es casi siempre igual para cada sistema
operativo, he incluso hay sistemas que se pueden identificar por medio
de este metodo, ya que son los unicos que le asignan cierto valor a
dicha ventana (ej. AIX, 0x3F25).
En lo que se refiere a sistemas linux, freebsd o solaris
tienden a mantener el mismo tamaño de ventana para cada sesion. En
cambio, cisco o Microsoft Windows/NT cambia constantemente.
$ hping2 localhost
...
y al analizar, por ejemplo dos de los paquetes con ethereal vemos:
Window Size: 512 (0x0200)
...
Window Size: 512 (0x0200)
- Tratamiento de fragmentacion: Se basa en el hecho de que los
sitemas operativos tratan de diferente forman los fragmentos de IP
solapados; mientras algunos mantienen el material inicial, otros
sobreescriben la porciones antiguas con las nuevas. De dificil
implementacion puesto que hay sistemas operativos que no permiten
mandar fragmentos de IP (lease Solaris), pero si que es cierto que
tendria bastante utilidad.
No lo he analizado en la practica, ya que no encontre la forma
de hacerlo con hping2 y el hacer un codigo que lo haga no me parece
materia para cubrir en este manual por tener bastante dificultad.
- Synflood: una tecnica que no me parece aplicable, por
razones bien marcadas. Hay ciertos OSs que llega un momento en que no
aceptan nuevas conexiones si has mandado demasiados paquetes SYN y por
ejemplo algunos sistemas operativos solo admiten 8 paquetes. Linux,
evita esto por medio de las SYN cookies.
- Nukes: Como ya he dicho anteriormente, la pila de Win95,
WinNT o Win98 parece identica. Para distinguir entre una u otra el
metodo que propongo es el aplicar nukes de forma cronologica (es
decir, de mas antiguos a mas nuevos) e ir viendo si el servidor se
cuelga o no; de esta forma sabremos la version ya que si sabemos que
un nuke (por ejemplo, Winnuke) solo funciona con Win95 pues ya
tendremos el OS. Aun asi, no recomiendo este metodo por razones
obvias. Actualmente, estoy a la espera de que mixter me aclare si el
ha conseguido alguna forma de distinguir una pila en win* en su
nsat. De decirme como, lo incluire en este texto.
Continuación
-----------------------------------------------------
II Analisis basado en la pila TCP/IP
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Antes de pasar a enumerar los programas que han hecho posible
el reconocimiento del sistema operativo de un host de forma remota me
parece logico explicar, a grandes rasgos, cual es su funcionamiento,
sin entrar de momento en particularidades.
Dichos programas basan su funcionamiento en analizar las
diferentes respuestas que ofrecen distintos sistemas ante ciertos
envios (he aqui las singularidades y la variedad de metodos). Por
tanto, dichas respuestas, que son comunmente conocidas como TCP/IP
fingerprints, son las que permiten distinguir un sistema operativo de
otro. Muchas veces, recurren dichos programas a distintos tipos de
envios ya que, en muchas ocasiones, las diferencias en la pila TCP/IP
de un sistema operativo a otro no son muy marcadas y ante ciertos
envios actuan de igual forma, diferenciandose, a veces, solo en uno o
incluso no habiendo diferencia (como en el caso de Windows 95/98/NT,
en los que increiblemente no se observa un comportamiento diferente en
sus pilas TCP/IP; unicamente probando nukes contra dichos hosts y
viendo si se caen o no, para asi distinguir por ejemplo entre un 95 y
un 98 (ej. WinNuke)).
Entre los programas disponibles que utilizan dicha tecnica de
fingerprinting destacan:
-spoofer para IRC sirc (Johan)
-checkos (shok)
-nmap (fyodor)
-nsat (mixter)
-p0f (Michal Zalewski)
-SS (Su1d)
-queso (savage)
Ya entrando mas a fondo en el funcionamiento a mas bajo nivel
de dichos programas encontramos cierta diferencia entre ellos, ya que
mientras unos usan un fichero externo con fingerprints de diferentes
sistemas tipo, como el queso, otros incluyen en el codigo dicha
comparacion, como checkos por ejemplo.
En checkos encontramos:
...
if ((tcp.hrc & CF_SYN) && (tcp.hrc & CF_FIN)) {
type=OS_LINUX;
done=1;
}
...
if ((tcp.hrc & CF_ACK) && (tcp.hrc & CF_RST)) {
if (flags & OSD_WIN95WAIT) {
done=1;
type=OS_WIN95;
}
En ss encontramos:
/* fragmento codigo de ss de Remote OS
Detection via TCP/IP Fingerprinting de
Fyodor */
...
if ((flagsfour & TH_RST) && (flagsfour & TH_ACK) && (winfour == 0) &&
(flagsthree & TH_ACK))
reportos(argv[2],argv[3],"Livingston Portmaster ComOS");
...
Mientras que en queso encontramos un fichero de configuracion
en el que se distingue por ejemplo:
$ cat /etc/queso.conf
...
* AS/400 OS/400 V4R2 (by rodneybrown@pmsc.com)
0 1 1 1 SA
1 0 1 0 R
2 0 1 0 RA
3 0 1 0 R
4 1 1 1 SA
5 0 1 0 RA
6 1 1 1 SA
...
Se observa, pues, que savage ha implementado de forma bastante
mas inteligente dicha idea. Este metodo ha sido heredado por fyodor
para su nmap, y por ejemplo, en ciertas versiones de nmap encontramos:
$ cat /usr/local/lib/nmap/nmap-os-fingerprints
...
# Thanks to Juan Cespedes <cespedes@lander.es>
FingerPrint AGE Logic, Inc. IBM XStation
TSeq(Class=64K)
T1(DF=N%W=2000%ACK=S++%Flags=AS%Ops=M)
T2(Resp=N)
T3(Resp=Y%DF=N%W=2000%ACK=O%Flags=A%Ops=)
T4(DF=N%W=2000%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=F%RIPCK=0%UCK=E%ULEN=134%DAT=E)
...
Y tambien ha sido usado por mixter en su NSAT, destacando la
distincion que hace entre diferentes configuraciones de windows:
$ cat /usr/local/bin/nsat.os
...
Windows (Firewall-1)
1 1 1 0 1 18
1 0 1 0 0 4
1 0 1 0 1 21
1 0 1 0 1 21
1 1 1 0 1 18
1 0 1 0 1 28
0 0 0 0 0 0
...
En lo que se refiere al tipo de tecnicas usadas para
diferenciar unos OSs se debe puntualizar que en realidad, estas
pruebas se combinan, para asi conseguir aislar cada sistema
operativo. Un muy buen programa para hacer este tipo de pruebas es el
hping2 (antirez@invece.org, http://www.kyuzz.org/antirez/hping2.html)
o sing (aandres@mfom.es, http://sourceforge.net/projects/sing/)
combinandolo con el analisis mediante tcpdump o ethereal (un magnifico
frontend), ya que aunque puedes realizar tu propio codigo (en C, por
ejemplo) esta claro que esto conlleva unos conocimientos de unix
network programing bastante importantes, asi que en este paper
analizare los resultados obtenidos con hping2 y no presentare codes
especificos para cada prueba, además utilizare mi propia maquina para
dichas pruebas y no lo hare de forma remota para asi tener un mayor
control de los resultados. Los metodos que conozco son: (si conoces
otras tecnicas utilizadas para esto no dudes en decirmelo -
honoriak@mail.ru)
- TCP ISN: Cuando el host a analizar responde a solicitudes de
conexion, genera unos numeros en la secuencia inicial (ISN) que no
siempre se producen de la misma forma; esto, es aprovechado para
distinguir unos sistemas de otros. Estos ISNs pueden ser constantes
(hubs de 3com, etc.), 64K (UNIX antiguos), aleatorios (linux >2.0, AIX
modernos, OpenVMS), incremento en funcion del tiempo (windows), de
incremento aleatorio (freebsd, digital unix, cray, solaris
modernos...) siendo estos ultimos incrementos basados en diferentes
cosas como por ejemplo maximos comunes divisores.
Si enviamos varios paquetes, por ejemplo, de la forma:
$ hping2 localhost -p 80
default routing not present
HPING localhost (lo 127.0.0.1): NO FLAGS are set, 40 headers + 0 data
bytes
40 bytes from 127.0.0.1: flags=RA seq=0 ttl=255 id=5 win=0 rtt=0.4 ms
40 bytes from 127.0.0.1: flags=RA seq=1 ttl=255 id=6 win=0 rtt=24.9 ms
--- localhost hping statistic ---
2 packets tramitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.4/12.6/24.9 ms
Y ahora analizamos dichos paquetes por ejemplo con el tcpdump
(mas claro son los resultados que ofrece ethereal, pero para copiar
aqui es mas comoda la salida del tcpdump; solo copiare las respuestas,
no las peticiones)
...
14:12:47.774380 lo < honorato.2485 > honorato.www: . 7200421:72
00421(0) win 512
...
14:12:48.771779 lo < honorato.2486 > honorato.www: . 2002659674:200
2659674(0) win 512
...
Se observa, pues, una variacion en la seq inicial del paquete
TCP, en el primer paquete vemos 7200421 y en el segundo 2002659674
siendo en este caso completamente aleatorios ya que estoy trabajando
en:
$ uname -a
Linux honorato.com 2.2.16 #14 SMP Sat Jun 10 15:51:08 CEST 2000
i86 unknown
- Opciones de TCP: esta tecnica se basa en el diferenciar
sistemas operativos segun el numero de opciones TCP que admiten, los
valores de dichas opciones y el orden en que las opciones se nos
presentan. Esto, que yo sepa, solo es utilizado por Nmap (si sabes de
otros programas que lo usen, no dudes en decirmelo y modificare esto).
Fyodor en su nmap hace prueba las siguientes opciones:
Window Scale=10; NOP; Max Segment Size = 265; Timestamp; End of Ops;
El hping2 no implementa esta posibilidad (o eso creo) asi que
no lo he llevado a la practica. Siempre puedes analizar el codigo del
nmap que realiza esto y heredar dicha tecnica.
- FIN: Se basa en el envio a un puerto abierto del host a
estudio de un paquete FIN o cualquiera que no tenga un flag ACK o
SYN. Segun el RFC793 el host no tendria que responder pero algunos OSs
responden con un RESET como Windows, HP/UX, IRIX, MVS, BSDI, CISCO.
Para hacer una prueba practica usare el puerto 80, con apache
arrancado:
$ /usr/bin/httpd
$ hping2 localhost -p 80 -F
default routing not present
HPING localhost (lo 127.0.0.1): F set, 40 headers + 0 data bytes
--- localhost hping statistic ---
4 packets tramitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms
Se observa pues, como mi linux si que cumple el RFC793 y no responde a
dichos paquetes.
- ACK recibido: El valor de ACK que nos envia el servidor a
analizar cuando por ejemplo enviamos un SYN|FIN|URG|PSH a un puerto
abierto o un FIN|PSH|URG a un puerto cerrado puede variar respecto al
numero de secuencia inicial que envia este.
Para probar, inicialmente mandare un paquete normal a un
puerto cerrado, y se comprueba que el valor de ACK no cambia y despues
uno FIN|PSH|URG tambien a un puerto cerrado y se vera como cambia:
$ killall httpd
$ hping2 localhost -p 80
...
y en la salida del tcpdump se ve
15:59:37.442157 lo > honorato.1676 > honorato.www: . 1752870898:1752
870898(0) win 512
15:59:37.442157 lo < honorato.1676 > honorato.www: . 1752870898:1752
870898(0) win 512
15:59:37.442259 lo > honorato.www > honorato.1676: R 0:0(0) ack 1752
870898 win 0
vemos como 1752870898 se mantiene en el ack, pero en cambio:
$ hping2 localhost -p 80 -S -F -U -P
...
y en la salida del tcpdump ahora vemos
16:00:48.480252 lo > honorato.2669 > honorato.www: SFP 1376153753:13
76153753(0) win 512 urg 0
16:00:48.480252 lo < honorato.2669 > honorato.www: SFP 1376153753:13
76153753(0) win 512 urg 0
16:00:48.480334 lo > honorato.www > honorato.2669: R 0:0(0) ack 1376
153754 win 0
Se ve pues como ha cambiado el valor de seq respecto al de ack
de 1376153753 a 1376153754.
De la misma forma, haciendo dicha prueba para un puerto
abierto se puede ver que hay una variacion. En estas pruebas he usado
linux, pero de un sistema a otro esa variacion puede ser diferente (lo
que permite diferenciarlos, claro esta).
- Flag TCP (64/128) en el encabezado TCP de un paquete SYN:
Haciendo esto, por lo que yo he probado/leido unicamente el linux
2.0.35 mantiene dicha flag en la respuesta y el resto cancela la
conexion. Esto, de estudiarse a fondo, puede servir para diferenciar
OSs.
No he hecho una demostracion practica de dicho metodo, ya que
en este momento no tengo instalado el kernel 2.0.35, pero simplemente
se haria: hping2 localhost -p 80 -S y se analizarian los resultados
vertidos por el tcpdump.
- ICMP:
1) Esta tecnica se basaria en el control del numero de
mensajes de destination unreachable que envia un host por ejemplo al
mandar un gran numero de paquetes a un puerto UDP. En linux,
encontramos como limita dicha cantidad de mensajes, y por ejemplo:
$ cat /usr/src/linux/net/ipv4/icmp.c
...
* 4.3.2.8 (Rate Limiting)
* SHOULD be able to limit error message rate (OK)
* SHOULD allow setting of rate limits (OK, in the source)
...
Pero, esta tecnica es de dificil implementacion, ya que habria
que considerar la posibilidad de que los paquetes se perdiesen.
$ hping2 localhost --udp -i u[intervalo_en_microsegundos]
...
--- localhost hping statistic ---
*** packets tramitted, * packets received, ***% packet loss
round-trip min/avg/max = *.*/*.*/*.* ms
Y se analizaria si limita o no el numero de paquetes de ICMP
Port Unreachable. Pero, no hago la prueba con mi localhost ya que las
condiciones son completamente diferentes a las condiciones que te
encontrarias en internet. Aun asi, veo de dificil implementacion esta
tecnica por lo dicho anteriormente.
2) Basandose en los mensajes de error ICMP, y centrandose en
los mensajes que se refieren a que no se pudo alcanzar un puerto casi
todos los OSs mandan simplemente el encabezado ip y ocho bytes; pero,
tanto solaris como linux mandan una respuesta un poco mas larga siendo
este ultimo el que responde con mayor numero de bytes. Esto, claro
esta, puede ser utilizado para distinguir unos OSs de otros.
$ hping2 localhost --udp -p 21
y si analizamos uno de los paquetes ICMP de Destination
unreachable observamos:
Header length: 20 bytes
Protocol: ICMP (0x01)
Data (28 bytes)
Type: 3 (Destination unreachable)
Code: 3 (Port unreachable)
se observa pues como en sistemas linux ademas del encabezado
ip se retornan bastante mas de 8 bytes, 28 bytes.
3) Fijandose nuevamente en los mensajes de error ICMP debido a
que no se pudo alcanzar un puerto, se observa que todos los OSs a
excepcion de linux usa como valor de TOS (tipo de servicio) 0, pero
linux en cambio, usa 0xc0 siendo esto parte del AFAIK, el campo de
referencia, que no es usado.
$ hping2 localhost --udp -p 21
y en el tcpdump, por ejemplo, observamos la siguiente salida:
16:27:57.052282 lo > honorato > honorato: icmp: honorato udp port fs
p unreachable [tos 0xc0]
16:27:57.052282 lo < honorato > honorato: icmp: honorato udp port fs
p unreachable [tos 0xc0]
siendo el tos 0xc0 como he expuesto anteriormente, ya que se
trata de un linux, a diferencia de los demas sistemas operativos.
4) Basandose en los encabezados de los paquetes ICMP de error
vemos como diferentes OSs lo utilizan como 'scratch space'. Es decir,
lo modifican; y asi por ejemplo encontramos como freebsd, openbsd,
ultrix... cambian el ID de la IP del mensaje original en su respuesta,
bsdi aumenta en 20 bytes la longitud total del campo de IP... (y hay
mas diferencias, que estan por analizar, asi que ya sabes).
En mi linux, por ejemplo, el un paquete udp al puerto 0 es:
0000 00 00 08 00 45 00 00 1c a4 c8 00 00 40 11 d8 06 ....E... ....@...
0010 7f 00 00 01 7f 00 00 01 0a e5 00 00 00 08 f6 f6 ........ ........
y su el paquete ICMP de Destination unreachable es:
0000 00 00 08 00 45 c0 00 38 22 de 00 00 ff 01 9a 24 ....E..8 "......$
0010 7f 00 00 01 7f 00 00 01 03 03 fb 18 00 00 00 00 ........ ........
0020 45 00 00 1c a4 c8 00 00 40 11 d8 06 7f 00 00 01 E....... @.......
0030 7f 00 00 01 0a e5 00 00 00 08 f6 f6 ........ ....
En linux, el campo de la IP, no varia del paquete udp al icmp
de error a diferencia de otros SOs pero pasa de tener id: 0xa4c8 a
tener id: 0x22de. Este metodo no lo he estudiado a fondo y veo que
puede tener bastantes particularidades. Si quieres tener una vision
un poco mas completa del escaneo de puertos mediante metodos basados
en ICMP puedes leer ICMP usage in scanning o tambien llamado
Understanding some of the ICMP Protocol's Hazards de Ofir Arkin de
Sys-security Group en http://www.sys-security.com.
5) Esta tecnica solo puede ser usada, en plataformas
unix/linux/bsd y no en win* ya que win no responde a las queries que
seran usadas, que son de ICMP tipo 13 o tambien conocidas como ICMP
Timestamp Request.
En el caso del sistema operativo linux, que es el que poseo
podemos observar la siguiente prueba:
$ sing -vv -tstamp 127.0.0.1 ...
del que se obtendra un tiempo de respuesta de timestamp que
puede ser utilizado para diferenciar unos OSs de otros.
6) Esta tecnica se basa en el funcinamiento especifico de los
routers.
En particular, se basa en ICMP Router Solicitation (ICMP de
tipo 10). Cada router 'multicastea' cada cierto tiempo un anuncio de
ruta (ICMP de tipo 9) desde cada una de sus interfaces de 'multicast',
y de esta forma anuncia la direccion IP del interfaz.
Si vemos que el host remoto responde con ICMP de tipo 9 frente
a un ICMP de tipo 10, entonces nos encontramos ante un router. Pero,
los routers que tengan suprimida esta caracteristica no seran
detectados.
Las pruebas para este metodo las puedes realizar tanto con
hping2 como con sing (antiguo icmpush), pero el ultimo fue el primero
en implementarla, y asi encontramos:
$ sing -rts 127.0.0.1
...
$ hping2 -C 10 127.0.0.1
...
- Bit no fragmentado: esta tecnica se basa en que ciertos
sistemas operativos ponen un bit no fragmentado de IP en algunos de
los paquetes que envian. Pero lo que es cierto es que no todos lo
hacen, y de hacerlo no lo hacen de la misma forma; lo que puede ser
aprovechado para averiguar el OS.
en mi linux (del que ya he copiado un uname -a antes, para
saber el kernel que uso):
$ hping2 localhost
...
al analizar uno de los paquetes tcp mandados con ethereal se
comprueba que:
Flags: 0x04
.1.. = Don't Fragment: Set
..0. = More fragments: Not set
pero, tampoco he hecho un gran numero de pruebas para asegurar
que en algun caso y con cierto tipo de paquetes no se adjunte dicho
bit. Aun asi, hay OSs que nunca lo usan como SCO o OpenBSD.
- La ventana inicial de TCP: se basa en la comprobacion de las
dimensiones de la ventana de los paquetes que nos devuelve el host a
estudiar. El valor que toma es casi siempre igual para cada sistema
operativo, he incluso hay sistemas que se pueden identificar por medio
de este metodo, ya que son los unicos que le asignan cierto valor a
dicha ventana (ej. AIX, 0x3F25).
En lo que se refiere a sistemas linux, freebsd o solaris
tienden a mantener el mismo tamaño de ventana para cada sesion. En
cambio, cisco o Microsoft Windows/NT cambia constantemente.
$ hping2 localhost
...
y al analizar, por ejemplo dos de los paquetes con ethereal vemos:
Window Size: 512 (0x0200)
...
Window Size: 512 (0x0200)
- Tratamiento de fragmentacion: Se basa en el hecho de que los
sitemas operativos tratan de diferente forman los fragmentos de IP
solapados; mientras algunos mantienen el material inicial, otros
sobreescriben la porciones antiguas con las nuevas. De dificil
implementacion puesto que hay sistemas operativos que no permiten
mandar fragmentos de IP (lease Solaris), pero si que es cierto que
tendria bastante utilidad.
No lo he analizado en la practica, ya que no encontre la forma
de hacerlo con hping2 y el hacer un codigo que lo haga no me parece
materia para cubrir en este manual por tener bastante dificultad.
- Synflood: una tecnica que no me parece aplicable, por
razones bien marcadas. Hay ciertos OSs que llega un momento en que no
aceptan nuevas conexiones si has mandado demasiados paquetes SYN y por
ejemplo algunos sistemas operativos solo admiten 8 paquetes. Linux,
evita esto por medio de las SYN cookies.
- Nukes: Como ya he dicho anteriormente, la pila de Win95,
WinNT o Win98 parece identica. Para distinguir entre una u otra el
metodo que propongo es el aplicar nukes de forma cronologica (es
decir, de mas antiguos a mas nuevos) e ir viendo si el servidor se
cuelga o no; de esta forma sabremos la version ya que si sabemos que
un nuke (por ejemplo, Winnuke) solo funciona con Win95 pues ya
tendremos el OS. Aun asi, no recomiendo este metodo por razones
obvias. Actualmente, estoy a la espera de que mixter me aclare si el
ha conseguido alguna forma de distinguir una pila en win* en su
nsat. De decirme como, lo incluire en este texto.