En primer lugar, existe una gran variedad de opciones para la manipulación de conjuntos de paquetes en Scapy que no se han comentado en las publicaciones anteriores, especialmente relacionadas con las funciones de Sniffing e importación/exportación de paquetes. Con la función sniff pueden realizarse ataques pasivos de recolección de paquetes con un nivel de personalización bastante óptimo, de una forma muy similar a lo que actualmente puede conseguirse con herramientas como wireshark o tcpdump, dado que es posible cargar un fichero PCAP capturado previamente, establecer filtros con la misma sintaxis que se utiliza en TCPDump, restringir el número de paquetes que el ataque reconocimiento podrá recolectar, etc. El uso de estas características es simple, tal y como se puede ver a continuación:

>>> sniff(filter=»host 192.168.1.33″)

^C

<Sniffed: TCP:1178 UDP:0 ICMP:0 Other:2>

>>> sniff(filter=»icmp», count=2)

<Sniffed: TCP:0 UDP:0 ICMP:2 Other:0>

>>> sniff(iface=»eth0″, filter=»tcp and port 80″, count=2)

<Sniffed: TCP:2 UDP:0 ICMP:0 Other:0>

>>> sniff(iface=»eth0″, filter=»tcp and port 80″, count=2, prn=lambda x: x.summary)

<bound method Ether.summary of <Ether dst=64:68:0c:45:71:88 src=54:42:49:fa:c1:0d type=0x800 |<IP version=4L ihl=5L tos=0x0 len=40 id=6638 flags=DF frag=0L ttl=64 proto=tcp chksum=0x5e47 src=192.168.1.33 dst=31.186.225.23 options=[] |<TCP sport=44508 dport=www seq=226196647 ack=3956530831 dataofs=5L reserved=0L flags=A window=341 chksum=0xe931 urgptr=0 |>>>>

<bound method Ether.summary of <Ether dst=64:68:0c:45:71:88 src=54:42:49:fa:c1:0d type=0x800 |<IP version=4L ihl=5L tos=0x0 len=52 id=59636 flags=DF frag=0L ttl=64 proto=tcp chksum=0xbeac src=192.168.1.33 dst=173.194.35.151 options=[] |<TCP sport=40546 dport=www seq=3930023807 ack=1339163708 dataofs=8L reserved=0L flags=FA window=1175 chksum=0x9fe6 urgptr=0 options=[(‘NOP’, None), (‘NOP’, None), (‘Timestamp’, (7641277, 1996876388))] |>>>>

<Sniffed: TCP:2 UDP:0 ICMP:0 Other:0>

>>> sniff(iface=»eth0″, filter=»tcp and port 80″, count=2, prn=lambda x: x.show())

###[ Ethernet ]###

dst= 64:68:0c:45:71:88

src= 54:42:49:fa:c1:0d

type= 0x800

###[ IP ]###

version= 4L

ihl= 5L

tos= 0x0

len= 52

id= 36709

flags= DF

frag= 0L

ttl= 64

proto= tcp

chksum= 0x6eda

src= 192.168.1.33

dst= 195.27.183.159

\options\

###[ TCP ]###

sport= 57773

dport= www

seq= 3708413643

ack= 3728792109

dataofs= 8L

reserved= 0L

flags= FA

window= 501

chksum= 0x7676

urgptr= 0

options= [(‘NOP’, None), (‘NOP’, None), (‘Timestamp’, (7652452, 1439058155))]

###[ Ethernet ]###

dst= 64:68:0c:45:71:88

src= 54:42:49:fa:c1:0d

type= 0x800

###[ IP ]###

version= 4L

ihl= 5L

tos= 0x0

len= 52

id= 25516

flags= DF

frag= 0L

ttl= 64

proto= tcp

chksum= 0x12d5

src= 192.168.1.33

dst= 23.66.235.55

\options\

###[ TCP ]###

sport= 46839

dport= www

seq= 1784893457

ack= 3512603310

dataofs= 8L

reserved= 0L

flags= FA

window= 80

chksum= 0xed61

urgptr= 0

options= [(‘NOP’, None), (‘NOP’, None), (‘Timestamp’, (7652452, 484216137))]

<Sniffed: TCP:2 UDP:0 ICMP:0 Other:0>

Una practica bastante común en procesos de pentesting, es el reconocimiento de la arquitectura empleada por emisores y receptores en un típico intercambio de paquetes TCP, las técnicas más comunes y conocidas para hacer esto, normalmente involucran herramientas tales como Queso, HPing o Nmap sin embargo, en la mayoría de los casos estas herramientas tienen mecanismos bastante “agresivos” para obtener dicha información y pueden generar alarmas en el host objetivo. Una solución elegante y sencilla, consiste en utilizar p0f.

QUE ES P0F?

Se trata de una herramienta sencilla que permite hacer OS Fingerprint (Detección de Sistema operativo) de forma pasiva. Esta corta descripción define claramente para lo que sirve esta librería, sin embargo va un poco más allá de la típica identificación del sistema operativo de un host determinado, también permite identificar detalles tales como el User-Agent, tiempo en el que la máquina se encuentra activa, Lenguaje utilizado por el cliente así como también el número de nodos (routers) por los que han tenido que viajar los paquetes (de un modo muy similar a como lo hace tracerouter).

Para realizar la identificación del sistema operativo, se apoya en una base de datos de “firmas” o comportamientos ya conocidos en la composición de distintos paquetes IP, dichas bases de datos se separan en dos secciones, en primer lugar se encuentran aquellas firmas que corresponden a “las máquinas que se conectan a mi máquina” y las firmas que corresponden a “las máquinas a las que se conecta mi máquina”. El primero de los casos se basa en un análisis de los paquetes SYN, mientras que el segundo se basa en un análisis de los paquetes SYN/ACK.

Ahora bien, su uso es simple, en primer lugar es necesario descargarlo desde http://lcamtuf.coredump.cx/p0f3/ (la versión actual es la 3.0.5) como se puede apreciar, se trata de una aplicación escrita en lenguaje C y que puede construirse utilizando el comando make

Una vez instalada la herramienta, su uso es simple, admite una serie de parámetros que determinan su comportamiento y comienza a “escuchar” paquetes en una o todas las interfaces de red del ordenador, del mismo modo que lo hacen herramientas como wireshark o tcpdump

>./p0f

— p0f 3.05b by Michal Zalewski <lcamtuf@coredump.cx> —

[+] Closed 1 file descriptor.

[+] Loaded 314 signatures from ‘p0f.fp’.

[+] Intercepting traffic on default interface ‘eth0’.

[+] Default packet filtering configured [+VLAN].

[+] Entered main event loop.

Las opciones de configuración que admite p0f son las siguientes

USANDO P0F

Existen algunas opciones de configuración muy útiles que permiten personalizar la ejecución de p0f ademas, tambien es posible utilizar filtros que se aplicarán a las funciones de captura de paquetes, siguiendo la misma sintaxis que se emplea para filtrar paquetes con tcpdump por ejemplo se puede aplicar el siguiente filtro (sintaxis de tcpdump) utilizando p0f

>./p0f «tcp and port 80»

Por otro lado, las opciones que resultan más interesantes y que se encuentran disponibles en esta herramienta son:

-i Definir que interfaz de red que utilizará para realizar la captura de paquetes

-r Opción empleada para leer “offline” ficheros de captura (pcap)

-p Permite poner la interfaz de red en modo promiscuo (en el caso de una red inalámbrica, será en modo monitor)

-L Listado de todas las interfaces de red disponibles

-o Admite un fichero donde se escribirán los registros de log

-f Permite especificar donde se encuentra la base de datos para realizar el proceso de OS Fingerprinting, por defecto dicho fichero se encuentra en el directorio raíz con el nombre p0f.fp

-u Permite ejecutar el comando con los privilegios de un usuario determinado

Algunos ejemplos del uso de dichas opciones:

>./p0f -i eth0 -p «tcp and port 80»

>./p0f -i eth0 -p -o log_file «tcp and port 80»

>./p0f -L

>./p0f -i eth0 -p -o log_file -u adastra «tcp and port 80»

>./p0f -r capture_file.pcap

Cuando p0f captura paquetes con filtros o sin filtros, intenta obtener tanta información como le sea posible de los participantes en la comunicación, los registros generados son similares a los siguientes

.-[ 192.168.1.33/35433 -> 72.233.111.159/80 (syn+ack) ]-

|

| server = 72.233.111.159/80

| os = Linux 3.x

| dist = 11

| params = none

| raw_sig = 4:53+11:0:1452:mss*10,9:mss,sok,ts,nop,ws:df:0

|

`—-

.-[ 192.168.1.33/35433 -> 72.233.111.159/80 (mtu) ]-

|

| server = 72.233.111.159/80

| link = DSL

| raw_mtu = 1492

|

`—-

.-[ 192.168.1.33/35433 -> 72.233.111.159/80 (uptime) ]-

|

| client = 192.168.1.33/35433

| uptime = 0 days 4 hrs 43 min (modulo 198 days)

| raw_freq = 252.14 Hz

|

`—-

.-[ 192.168.1.33/35426 -> 72.233.111.159/80 (http response) ]-

|

| server = 72.233.111.159/80

| app = ???

| lang = none

| params = none

| raw_sig = 1:Server,Date,Content-Type,Connection=[close],?Last-Modified,?ETag,Accept-Ranges=[bytes],?Content-Length:Keep-Alive:nginx

|

`—-

Como puede apreciarse, en este caso concreto, los registros enseñan 4 bloques de información relacionada al servidor 72.233.111.159 donde incluye información sobre:

  • Análisis syn+ack para determinar el sistema operativo del host remoto.

  • Obtención de los valores de transmisición de datos, (MTU)

  • Tiempo de actividad del sistema (UPTIME)

  • Contenido de la respuesta a un paquete enviado previamente por el cliente, en este caso se trata de una respuesta HTTP, por lo tanto el contenido incluye valores relacionados con los Headers de la respuesta HTTP.

La información que brinda esta herramienta es muy detalla y lo mejor, es que se trata de un reconocimiento pasivo, con lo cual no activará ningún tipo de alarma en el host remoto. Además de lo anterior, el hecho de poder filtrar los paquetes que realmente resultan interesantes utilizando los filtros que se disponen en tcpdump hacen que esta herramienta sea casi de carácter “obligatorio” dentro de la caja de herramientas de un pentester/hacker.

UTILIZANDO SCAPY Y P0F JUNTOS

Volviendo nuevamente a Scapy, es importante anotar que es posible utilizar p0f dentro de Scapy gracias a una utilidad muy robusta dentro de esta librería, se trata de la posibilidad de cargar módulos dentro del contexto de Scapy y posteriormente utilizar las funcionalidades de dichos módulos, los cuales son aplicaciones externas que normalmente suelen estar centradas en las etapas de reconocimiento y fingerprinting como es el caso de p0f o de nmap

Para activar p0f en Scapy, solamente es necesario cargar el modulo y posteriormente utilizar las variables y objetos existentes en el modulo cargado

>>> load_module(«p0f»)

>>> p = sniff(prn=prnp0f, filter=’tcp’)

En el ejemplo anterior, todos los paquetes que se capturen pasaran por la rutina prnp0f la cual se encargará de determinar el sistema operativo, tiempo de actividad y contenidos de las peticiones/respuestas.

El resultado de los comandos anteriores, será un largo listado con los resultados obtenidos por p0f, sin embargo tambien es posible ser más “especifico” y utilizar directamente la función p0f con un paquete previamente capturado, por ejemplo:

>>> p = sniff(filter=»tcp», count=20)

>>> p.nsummary()

0000 Ether / IP / TCP 173.194.34.54:https > 192.168.1.106:57699 PA / Raw

0001 Ether / IP / TCP 192.168.1.106:57699 > 173.194.34.54:https A

0002 Ether / IP / TCP 192.168.1.106:47293 > 69.171.247.69:www S

0003 Ether / IP / TCP 192.168.1.106:47294 > 69.171.247.69:www S

0004 Ether / IP / TCP 69.171.247.69:www > 192.168.1.106:47293 SA

0005 Ether / IP / TCP 192.168.1.106:47293 > 69.171.247.69:www A

0006 Ether / IP / TCP 192.168.1.106:47293 > 69.171.247.69:www PA / Raw

0007 Ether / IP / TCP 69.171.247.69:www > 192.168.1.106:47294 SA

0008 Ether / IP / TCP 192.168.1.106:47294 > 69.171.247.69:www A

0009 Ether / IP / TCP 69.171.247.69:www > 192.168.1.106:47293 A

0010 Ether / IP / TCP 69.171.247.69:www > 192.168.1.106:47293 A / Raw

0011 Ether / IP / TCP 192.168.1.106:47293 > 69.171.247.69:www A

0012 Ether / IP / TCP 69.171.247.69:www > 192.168.1.106:47293 A / Raw

0013 Ether / IP / TCP 192.168.1.106:47293 > 69.171.247.69:www A

0014 Ether / IP / TCP 69.171.247.69:www > 192.168.1.106:47293 A / Raw

0015 Ether / IP / TCP 192.168.1.106:47293 > 69.171.247.69:www A

0016 Ether / IP / TCP 69.171.247.69:www > 192.168.1.106:47293 PA / Raw

0017 Ether / IP / TCP 192.168.1.106:47293 > 69.171.247.69:www A

0018 Ether / IP / TCP 69.171.247.69:www > 192.168.1.106:47293 A / Raw

0019 Ether / IP / TCP 192.168.1.106:47293 > 69.171.247.69:www A

>>> p0f(p[3])

[(‘Linux’, ‘2.6 (newer, 3)’, 0)]

>>> p0f(p[4])

[]

Con lo anterior, se han enviado los paquetes 3 y 4 de aquellos que se han podido capturar con la función sniff y dicha función ha determinado la versión del sistema operativo, en el caso de que la información contenida en el paquete no permita obtener la versión del sistema operativo, la función simplemente devolverá un array vacío.

NOTA: En las ultimas versiones de P0F no se encuentran las bases de firmas necesarias por p0f para realizar la identificación de sistemas operativos, con lo cual es necesario descargarlas de forma independiente, he podido ver que se encuentran disponibles en la versión 2.0.8 (ver en el repositorio de descargas ubicado en el sitio web oficial, las versiones antiguas) en concreto son varios ficheros con extensión “fp” tales como p0fa.fp, p0fo.fp, p0h.fp, etc. Ubicar dichos ficheros en /etc/p0f para que Scapy pueda encontrarlos y utilizarlos.

Ahora bien, el modulo p0f contenido en Scapy tiene algunas funciones que resultan muy interesantes (para aquellos que tengan conocimientos en Python, quizás les resulte bastante útil ver el código fuente del modulo, que se encuentra incluido en <SCAPY_DIR>/scapy/modules/p0f.py) algunas de estas funciones permiten explotar las capacidades que brinda Scapy para manipular al gusto del programador, cualquier tipo de paquete y posteriormente enviarlo a un objetivo determinado, en este caso, la función p0f_impersonate es realmente interesante, ya que permite componer un paquete que coincida con una firma determinada, es decir, se puede construir un paquete que incluya valores personalizados en sus campos, de esta forma, el receptor de dicho mensaje obtendrá información falseada sobre cosas como por ejemplo, el sistema operativo desde donde se origino el paquete.

>>> pkt = p0f_impersonate(IP(dst=’www.target.com’)/TCP(sport=8080, dport=80, flags=’S’), osgenre=’Windows’)

>>> prnp0f(pkt)

192.168.1.106:http_alt – Windows ME no SP (?)

-> Net(‘www.target.com’):www (S) (distance 0)

>>> send(pkt)

.

Sent 1 packets.

Como puede verse, la función p0f_impersonate ha permitido generar un paquete que supuestamente se ha originado en un sistema operativo Windows, cuando se ha invocado a la función prnp0f el resultado de esta ha sido, Windows ME sin ningún Service Pack instalado… realmente divertido.

Ahora, cuando se envía dicho paquete a su destino, el destinatario solamente podrá obtener la información falseada que se ha incluido en dicho paquete.

La función p0f_impersonate tiene la siguiente firma:

def p0f_impersonate(pkt, osgenre=None, osdetails=None, signature=None,

extrahops=0, mtu=1500, uptime=None):

Así que no solamente admite el sistema operativo, también pueden incluirse otros detalles como numero de HOPS extra, MTU y tiempo de actividad.

Para mayor información sobre el uso de este modulo en Scapy, se recomienda echarle un vistazo al código fuente y las funciones disponibles.