CREACIÓN DE MÁSCARAS PARA FILTROS
Ocurre que en ocasiones nos encontramos con un byte que está dividido en dos partes, es decir, en dos campos de 4 bits cada uno.
Todo lo comentado anteriormente referente a filtros para extraer datos de las cabeceras, sólo es válido para un byte completo. Así que nos encontraremos con un problema cuando tengamos que descartar en un byte una parte de éste.
Ejemplo
Observemos el primer byte (8 bits primeros) de una cabecera IP.
[IMG]http://www.abance.es/fdw/byte_cabecera_IP.png[IMG]
Vemos que consta de dos partes:
1. la versión
2. el tamaño del encabezamiento (IHL)
Entonces queremos descartar los 4 bits de la versión IP y filtrar el tamaño del encabezamiento. ¿Cómo hacemos esto?.
La respuesta está en la creación de máscaras. Es decir, enmascarar unos bits para dejar "ver" el resto, y estas máscaras la hacemos usando operaciones booleanas. Lo vemos, como siempre, con un ejemplo:
Nos centramos en el primer byte de un encabezamiento IP. Tenemos los grupos de 4 bits. Vamos a explicar esto usando la misma técnica que en el capítulo II.
Dado que la versión de IP actualmente es la 4 y el tamaño del encabecamiento es 20 bytes ... vaya, pero ¿cómo puede ser que tenga 20 bytes? si los bits destinados a este campo son sólo 4. La razón está en que la medida de este campo se hace representándolo en palabras de 32 bits, o sea, en 4 bytes. Así que el valor real almacenado es de 5. Este 5 lo multiplicamos por 4 bytes y nos dá como resultado 20 bytes.
Representamos en binario abajo los dos valores; el 4 de la versión y el 5 del tamaño (con una calculadora podemos ver su valor en binario).
Versión IP Tamaño encabezamiento IP
0 1 0 0 0 1 0 1 (101: "4")
como queremos descartar la versión IP, vamos a realizar una operación booleana. Esta operación es un AND con 0 0 0 0 1 1 1 1
0 1 0 0 0 1 0 1
0 0 0 0 1 1 1 1
0 0 0 0 0 1 0 1
Razonemos este resultado. Si recordamos las operaciones booleanas:
0 AND 0 = 0
1 AND 0 = 0
1 AND 1 = 1
0 AND 1 = 0
Sólo en el caso de que los dos bits estén a 1 el resultado será 1.
Esta es la técnica que usa TCPDump / Windump para enmascarar bits. Pero ¿cómo traducimos esto a un filtro?
Recordemos que para crear un filtro de extración de datos de una cabecera se usa la expresión proto[x:y] = valor, en general expresión relación expresión. Veíamos en otros capítulos filtros como este:
C:\scan>windump -qn -X -s 0 tcp[13] = 2 and port 110
expresión: tcp[13]
relación: =
expresión: 2
pues bien, como ahora hablamos de encabezamiento IP y el primer byte, el filtro sería de esta forma:
expresión: ip[0]
Vamos ahora con el resto de la expresión. Como realizamos una operación boolena de AND (&):
expresión: ip[0] &
como el valor binario, la máscara que vamos a aplicar es 0000 1111 en hexadecimal es 0F e indicamos que es un valor hexadecimal con el valor 0x, entonces:
expresión: ip[0] & 0x0F
y ahora la relación. Vamos a filtrar los valores de longitud de encabecamiento IP mayores que 5:
expresión: ip[0] & 0x0F > 5
Este filtro sería un caso de comportamiento anormal. Para probrarlo usaremos otro valor:
expresión: ip[0] & 0x0F = 5
que sería el normal en una cabecera Ip sin datos. Lo probamos:
Código:
C:\scan>windump -qn "ip[0] & 0x0f > 5"
windump: listening on \Device\NPF_{604C8AE3-5FAC-45A5-BFAA-81175A8C32BF}
779 packets received by filter
0 packets dropped by kernel
C:\scan>windump -qn "ip[0] & 0x0f = 5"
windump: listening on \Device\NPF_{604C8AE3-5FAC-45A5-BFAA-81175A8C32BF}
18:40:02.766513 IP 192.168.4.15.8080 > 192.168.4.5.4261: tcp 1460
18:40:02.876720 IP 192.168.4.5.4261 > 192.168.4.15.8080: tcp 0 (DF)
18:40:02.891493 IP 192.168.2.70.1025 > 192.168.2.60.139: tcp 88 (DF)
18:40:02.891720 IP 192.168.2.60.139 > 192.168.2.70.1025: tcp 80 (DF)
18:40:02.896319 IP 192.168.2.70.1025 > 192.168.2.60.139: tcp 176 (DF)
18:40:02.896540 IP 192.168.2.60.139 > 192.168.2.70.1025: tcp 39 (DF)
18:40:02.901594 IP 192.168.4.15.8080 > 192.168.4.5.4261: tcp 1140
18:40:02.946950 IP 192.168.2.70.1025 > 192.168.2.60.139: tcp 64 (DF)
18:40:02.947377 IP 192.168.2.60.139 > 192.168.2.70.1025: tcp 1460 (DF)
18:40:02.947442 IP 192.168.2.60.139 > 192.168.2.70.1025: tcp 1460 (DF)
18:40:02.947543 IP 192.168.2.60.139 > 192.168.2.70.1025: tcp 1240 (DF)
18:40:02.947620 IP 192.168.2.70.1025 > 192.168.2.60.139: tcp 0 (DF)
18:40:03.010696 IP 192.168.4.15.8080 > 192.168.4.5.4227: tcp 190
18:40:03.069269 IP 192.168.2.70.1025 > 192.168.2.60.139: tcp 0 (DF)
*Hay que observar, como en ejemplos anteriores, que el filtro está entre comillas.
Es un tanto difícil de comprender el enmascaramiento pero lo vemos con otro ejemplo práctico.
Acabo de crear un filtro para TCP lo ejecuto y me da como respuesta:
Código:
C:\scan>windump -qn "tcp[13] & 0x02 != 0"
windump: listening on \Device\NPF_{604C8AE3-5FAC-45A5-BFAA-81175A8C32BF}
18:58:52.992949 IP 192.168.4.5.4483 > 192.168.4.15.8080: tcp 0 (DF)
18:58:52.993085 IP 192.168.4.15.8080 > 192.168.4.5.4483: tcp 0
18:58:55.909550 IP 192.168.2.5.3028 > 192.168.4.15.110: tcp 0 (DF)
18:58:55.909650 IP 192.168.2.5.3028 > 192.168.4.15.110: tcp 0 (DF)
18:58:55.909777 IP 192.168.4.15.110 > 192.168.2.5.3028: tcp 0
18:58:55.909879 IP 192.168.4.15.110 > 192.168.2.5.3028: tcp 0
18:58:56.130273 IP 192.168.2.5.3029 > 192.168.4.15.110: tcp 0 (DF)
18:58:56.130343 IP 192.168.2.5.3029 > 192.168.4.15.110: tcp 0 (DF)
18:58:56.130483 IP 192.168.4.15.110 > 192.168.2.5.3029: tcp 0
18:58:56.130560 IP 192.168.4.15.110 > 192.168.2.5.3029: tcp 0
18:58:56.348314 IP 192.168.2.5.3030 > 192.168.4.15.110: tcp 0 (DF)
18:58:56.348379 IP 192.168.2.5.3030 > 192.168.4.15.110: tcp 0 (DF)
18:58:56.348522 IP 192.168.4.15.110 > 192.168.2.5.3030: tcp 0
18:58:56.348598 IP 192.168.4.15.110 > 192.168.2.5.3030: tcp 0
18:58:58.003782 IP 192.168.4.5.4485 > 192.168.4.15.8080: tcp 0 (DF)
18:58:58.003924 IP 192.168.4.15.8080 > 192.168.4.5.4485: tcp 0
18:58:58.008186 IP 192.168.4.5.4487 > 192.168.4.15.8080: tcp 0 (DF)
El hecho de crear un filtro TCP del tipo tcp[13] tiene una razón: en parte está explicado en el capítulo I :
El siguiente octeto es el 12 (el décimo tercero) va desde el bits 0 al 7 que corresponden a posición de datos u offset -4 bits- y a Reservado -4+2-; dos bits de Reservado pertenecen ya al siguiente octeto el 13, que tiene los 2 bits reservados anteriores y 6 que son los flags (UAPRSF). 6 + 2 = 8 bits que es el octeto o byte 13 (o décimo cuarto).
Vamos a analizar ahora de donde viene el valor 2 de la expresión tcp[13] = 2
Esta es la representación de octeto ó byte 13. Si ponemos el flag SYN activado y el resto NO activados, resulta que SYN lo ponemos a 1 y el resto a 0:
Queda entonces: 0 0 0 0 0 0 1 0 (los dos primeros bits dijimos que eran reservados y siempre están a 0)
U A P R S F
------------------
0 0 0 0 0 0 1 0 (en binario)
------------------
7 6 5 4 3 2 1 0
"tcp[13] & 0x02 != 0"
Como ya sabemos de donde biene la expresión tcp[13], seguimos con el resto. Vemos en la expresión que realizamos una operación booleana de tipo AND (&) y que la expresión 02 está expresada en hexadecimal (0x). El valor binario de la expresión 02 es 10. Si miramos el cuadro anterior:
U A P R S F
------------------
0 0 0 0 0 0 1 0 (en binario)
------------------
7 6 5 4 3 2 1 0
Vemos que se trata de la activación del flag SYN. Seguimos con el filtro y vemos que además tiene != 0, es decir, que sea distinto de 0. Realicemos la operación de enmascaramiento.
0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0
Según esto, si aplicamos la máscara 0x02, el resultado es 0, pero si nos dá como resultado algo distinto de 0 entonces no estaría activado el flag SYN.
Este filtro es por tanto para detectar el flag SYN activado en una conexión TCP. Es decir es el mismo filtro que el del ejemplo del capítulo I:
Código:
C:\scan>windump -qn "tcp[13] = 2"
windump: listening on \Device\NPF_{604C8AE3-5FAC-45A5-BFAA-81175A8C32BF}
19:26:29.583511 IP 192.168.4.5.4851 > 192.168.4.15.8080: tcp 0 (DF)
19:26:39.586494 IP 192.168.4.5.4853 > 192.168.4.15.8080: tcp 0 (DF)
19:26:50.602742 IP 192.168.4.5.4855 > 192.168.4.15.8080: tcp 0 (DF)
Ambos filtros son lo mismo. Nos devuelven el mismo resultado.
Hasta la próxima.
(c) Alfon.