Scapy. Manipulación avanzada e interactiva de paquetes. Parte 4

Ya vimos en la primera, segunda y tercera parte de esta serie dedicada a Scapy, conceptos como: funciones de sniffer, creación de gráficas 2D / 3D / Pdf,  passive OS fingerprinting, tracers gráficos, formateo de datos, lectura y escritura .pcap, funciones gráficas, clases y directivas, modo offline, conversations, instalacion en windows, uso en linux, etc,

Scapy. Creacion envio y manipulacion paquetes es Seguridad y   Redes. Alfon

En esta ocasión vamos a estudiar la creación, manipulado y envio de paquetes a través de scapy. Usaremos también Tshark para ver los resultados del envío de paquetes y algunos ataques y escaneos que simularemos para ilustrar mejor la creación y envio de paquetes.

Construyendo paquetes y encabezados. 

Ya vimos en la primera parte  de esta serie algo sobre la contrucción de paquetes de una forma básica. Vamos ahora, con ejemplos, a ir avanzando un poco más. Eso si, explicando paso a paso y de forma sencilla.

Función IP()

Con esta función podemos crear y manipular, por ejemplo, encabezados IP. Además de crear otros paquetes incluyendo otros protocolosencapsulados como ICMP , UDP y TCP.

Por defecto, estos son los campos IP, si no establecemos ninguno,  cuando creamos de la forma más basica un paquete IP:

>>> a=IP()
>>> a.show()
###[ IP ]###
version= 4
ihl= None
tos= 0x0
len= None
id= 1
flags=
frag= 0
ttl= 64
proto= ip
chksum= None
src= 127.0.0.1
dst= 127.0.0.1
\options\

Podemos añadir algún valor de campos:

>>> a=IP(ttl=»10″,src=»192.168.1.234″,dst=»192.168.1.5«,flags=1)
>>> a.show()
###[ IP ]###
version= 4
ihl= None
tos= 0x0
len= None
id= 1
flags= MF
frag= 0
ttl= ’10’
proto= ip
chksum= None
src= 192.168.1.234
dst= 192.168.1.5
\options\

Hemos añadido el valor TTL, IP origen, IP destino y flags ó banderas. IP origen que no tiene que ser el real desde donde enviamos o creamos un paquete.

Otra forma de mostrar el paquete es:

>>> ls(a)
version    : BitField             = 4               (4)
ihl        : BitField             = None            (None)
tos        : XByteField           = 0               (0)
len        : ShortField           = None            (None)
id         : ShortField           = 1               (1)
flags      : FlagsField           = 1               (0)
frag       : BitField             = 0               (0)
ttl        : ByteField            = ’10’            (64)
proto      : ByteEnumField        = 0               (0)
chksum     : XShortField          = None            (None)
src        : Emph                 = ‘192.168.1.234’ (None)
dst        : Emph                 = ‘192.168.1.5’   (‘127.0.0.1’)
options    : PacketListField      = []              ([])

Función ICMP() 

Lo mismo podemos hacer con ICMP. Los campos que podemos manipular son:

>>> a=ICMP()
>>> ls(a)
type       : ByteEnumField        = 8               (8)
code       : MultiEnumField       = 0               (0)
chksum     : XShortField          = None            (None)
id         : ConditionalField     = 0               (0)
seq        : ConditionalField     = 0               (0)
ts_ori     : ConditionalField     = 47756788        (47756788)
ts_rx      : ConditionalField     = 47756788        (47756788)
ts_tx      : ConditionalField     = 47756788        (47756788)
gw         : ConditionalField     = ‘0.0.0.0’       (‘0.0.0.0’)
ptr        : ConditionalField     = 0               (0)
reserved   : ConditionalField     = 0               (0)
addr_mask  : ConditionalField     = ‘0.0.0.0’       (‘0.0.0.0’)
unused     : ConditionalField     = 0               (0)

Vamos a crear una cabecera ICMP para un tipo concreto de mensaje ICMP, en este caso Time to Live exceeded in Transit:

>>> b=ICMP(type=11,code=0,seq=3334)
>>> b.show()
###[ ICMP ]###
type= time-exceeded
code= ttl-zero-during-transit
chksum= None
unused= 0

Dependiendo del tipo y código, podemos crear diferentes cabeceras de mensajes ICMP.

Función TCP() y UDP()

De forma análoga, podemos crear cabeceras TCP y UDP.

>>> c=TCP(sport=1024,dport=80,seq=477645,flags=»S»)
>>> c.show()
###[ TCP ]###
sport= 1024
dport= www
seq= 477645
ack= 0
dataofs= None
reserved= 0
flags= S
window= 8192
chksum= None
urgptr= 0
options= {}

Hemos creado una cabecera TCP con los valores personalizados de puerto origen, puerto destino, número de secuencia y flags establecido en S, un paquete SYN.

Creación y envío básico de paquetes.

Según lo visto hasta ahora, podemos crear el paquete completo con sus cabeceras encapsuladas. Por ejemplo un paquete ICMP:

>>> a=IP(src=»192.168.1.234″,dst=»192.168.1.5″)
>>> b=ICMP(type=11,code=0,seq=3334)

y lo enviamos con la función sr(). Esta función envia y recive paquetes para la capa 3.

>>> sr(a/b)
Begin emission:
Finished to send 1 packets.
.*
Received 2 packets, got 1 answers, remaining 0 packets
(, )

Esto es lo mismo que:

sr(IP(src=»192.168.1.234″,dst=»192.168.1.5″)/ICMP(type=11,code=0,seq=3334))

O también:

sr(a/ICMP(type=11,code=0,seq=3334)

La función display() la podemos usar para ver la estrucura y valores de campos de los paquetes:

>>> paquete=(IP(src=»192.168.1.234″,dst=»192.168.1.5″)/ICMP(type=11,code=0,seq=3334))
>>> paquete.display()
###[ IP ]###
version= 4
ihl= None
tos= 0x0
len= None
id= 1
flags=
frag= 0
ttl= 64
proto= icmp
chksum= None
src= 192.168.1.234
dst= 192.168.1.5
\options\
###[ ICMP ]###
type= time-exceeded
code= ttl-zero-during-transit
chksum= None
unused= 0

Concatenación básica de cabeceras y protocolos.

Se pueden crear paquetes de muchas formas, casi depende de la imaginación y del uso de variables:

>>> ip=IP(dst=»192.168.1.5″,src=»192.168.1.45″,flags=1)
>>> udp=UDP(sport=2048,dport=445)
>>> payload=«Estoy construyendo un paquete»
>>> paquete=
ip/udp/payload
>>> paquete.display()
###[ IP ]###
version= 4
ihl= None
tos= 0x0
len= None
id= 1
flags= MF
frag= 0
ttl= 64
proto= udp
chksum= None
src= 192.168.1.45
dst= 192.168.1.5
\options\
###[ UDP ]###
sport= 2048
dport= microsoft_ds
len= None
chksum= None
###[ Raw ]###
load= ‘Estoy construyendo un paquete’

Uso de campos aleatorios. RandShort().

Con RandShort(), scapy crea un valor aleatorio para un determinado campo. Vamos a enviar a la IP 192.168.1.5 4 paquetes a los puertos 80,110,143 y 21, usando puertos origen aleatorios:

>>> sr(IP(dst=»192.168.1.5″)/TCP(sport=RandShort(),dport=[80,110,143,21],flags=»S»))
Begin emission:
****Finished to send 4 packets.

Received 4 packets, got 4 answers, remaining 0 packets
(, )

Vamos a ver que paquetes envió con sr() y que puertos origen usó scapy:

>>> ans,unans =_
>>> ans.summary()
IP / TCP 192.168.1.45:56482 > 192.168.1.5:www S ==> IP / TCP 192.168.1.5:www > 192.168.1.45:56482 SA / Padding
IP / TCP 192.168.1.45:30384 > 192.168.1.5:pop3 S ==> IP / TCP 192.168.1.5:pop3 > 192.168.1.45:30384 RA / Padding
IP / TCP 192.168.1.45:34786 > 192.168.1.5:imap2 S ==> IP / TCP 192.168.1.5:imap2 > 192.168.1.45:34786 RA / Padding
IP / TCP 192.168.1.45:63351 > 192.168.1.5:ftp S ==> IP / TCP 192.168.1.5:ftp > 192.168.1.45:63351 RA / Padding
>>>

Add.payload()

Vamos hora a aplicar todo lo aprendido hasta ahora en un sencillo ejemplo y añadimos add.payload() para insertar datos y enviamos mediante sr1 (veremos más abajo sr1):

Scapy. Creacion envio y manipulacion paquetes es Seguridad y  Redes. Alfon

Ahora la respuesta en destino mediante Tshark:

Scapy. Creacion envio y manipulacion paquetes es Seguridad y  Redes. Alfon

Vemos en ambas capturas el contenido del  payload «Hola voy dentro de un icmp».

Enviando paquetes

Para enviar paquetes mediante scapy, tenemos varias funciones, podemos destacar:

  • sr: Envía paquetes y recive todas las respuestas en la capa  3.
  • sr1: Envía paquetes y recive la primera respuestas en la capa  3.
  • srbt: Envía y recibe usando bluetooth socket.
  • srbt1: Envía y recive 1 respuesta usando a bluetooth socket.
  • srloop: Envia un paquete para la capa 3 en de forma cíclica e imprime una sola respuesta cada vez.
  • srp: Envía y recive paquetes para la capa 2
  • srp1: Envia y recive paquetes para la capa 2. Recive el primer paquete de respuesta.
  • send: Envía paquetes para la capa 3

Vamos a ver todo esto con ejemplos.

Con send solo enviamos paquetes sin esperar respuesta de ningún tipo:

>> send(IP(dst=»192.168.1.5″)/TCP(dport=[80,110,25],flags=»S»))

Sent 3 packets.

Con sr, enviamos los paquetes y recivinos todas las respuestas:

>>> sr(IP(dst=»192.168.1.45″)/TCP(dport=[80,110,25],flags=»S»))
Begin emission:
.Finished to send 3 packets.
*.*…………………..^C
Received 27 packets, got 2 answers, remaining 1 packets
(, )

Vemos más arriba Results: TCP:2, ¿ y cuales son esos 2 resultados ?:

>>> ans, unans=_
>>> ans.summary()
IP / TCP 192.168.1.88:ftp_data > 192.168.1.45:smtp S ==> IP / TCP 192.168.1.245:smtp > 192.168.1.88:ftp_data RA / Padding
IP / TCP 192.168.1.88:ftp_data > 192.168.1.45:www S ==> IP / TCP 192.168.1.245:www > 192.168.1.88:ftp_data RA / Padding

Otra forma de implementar sr para, por ejemplo, descubrir hosts e imprimir en pantalla aquellos que esten «activos». Usamos para ello las funciones ya estudiadas sprint(), y lambda():

>>> ans,unans = sr(IP(dst=»192.168.1.5-30″)/TCP(dport=80,flags=»A»))
Begin emission:
……..

…………………^C
Received 82 packets, got 6 answers, remaining 20 packets
>>> ans.summary(lambda (s,r): r.sprintf(El host: «%IP.src% está activo. «) )
El host: 192.168.1.5 está activo.
El host:192.168.1.10 está activo.
El host:192.168.1.11 está activo.
El host:192.168.1.28 iestá activo.
El host:192.168.1.29 está activo.
El host:192.168.1.30 está activo.

Podríamos, haciendo uso de python:

>> for a, b in ans:
…     print a.dst, «port», a.dport, «abierto»

192.168.1.5 port 80 abierto
192.168.1.10 port 80 abierto
192.168.1.11 port 80 abierto
192.168.1.28 port 80 abierto
192.168.1.29 port 80 abierto
192.168.1.30 port 80 abierto

Con sr1 enviamos los paquetes y esperamos…:

>>> sr1(IP(dst=»192.168.1.45″)/TCP(dport=[80,110,25],flags=»S»))
Begin emission:
.Finished to send 3 packets.
**…………….^C
Received 19 packets, got 2 answers, remaining 1 packets
>>

Haciendo uso de python:

p=IP(dst=»192.168.1.1/24″)/TCP(dport=139, flags=»S»)
sr(p)
>>> resultado = _[0]
>>> for a,b in resultado:
…     if b.flags == 2:
…           print a.dst

192.168.1.5
192.168.1.10
192.168.1.11
192.168.1.28
192.168.1.29
192.168.1.30
192.168.1.36
192.168.1.55
192.168.1.61
192.168.1.89
192.168.1.175
192.168.1.232
192.168.1.237
192.168.1.242
192.168.1.246

Enviamos paquetes al puerto de destino 139 y con el flag SYN activado. Imprimimos en pantalla los que tengan activado elvalor 2 en el campo Flags (FlagsField).

Ahora enviamos paquetes mediante sr1 y formateamos los resultados de forma personalizada extrayendo los resultados mediante el operador lambda y sprintf() que vamos a recordar….:

  • sprinft() Para dar formato a una cadena vlcándola a una variable. No es propia de Python.
  • lambda: El operador lambda de Python, sirve para crear funciones anónimas en línea. Al ser funciones anónimas, es decir, sin nombre, estas no podrán ser referenciadas más tarde.

    Las funciones lambda se construyen mediante el operador lambda, los parámetros de la función separados por comas , dos puntos (:) y el código de la función.

  • con _ en ans,unans=_ lamacenamos el resultado anterior.

el ejemplo:

>> sr(IP(dst=»192.168.1.5″)/TCP(sport=RandShort(),dport=[80,443,24,110],flags=»S»))
Begin emission:
.*.***Finished to send 4 packets.

Received 6 packets, got 4 answers, remaining 0 packets
(, )
>>> ans,unans = _
>>> ans.summary( lambda(s,r): r.sprintf(«%TCP.sport% \t %TCP.flags%») )
www      SA
https    SA
24       RA
pop3     RA

Nos complicamos un poco más y creamos una tabla con los resultados:

>>> ans,unans = sr(IP(dst=[«192.168.1.5″,»192.168.1.11″,»192.168.1.10″])/TCP(dport=[22,80,443],flags=»S»))
Begin emission:
..***.**.*.*Finished to send 9 packets.
**
Received 14 packets, got 9 answers, remaining 0 packets
>>> ans.make_table(
…      lambda(s,r): (s.dst, s.dport,
…      r.sprintf(«{TCP:%TCP.flags%}{ICMP:%IP.src% – %ICMP.type%}»)))
    192.168.1.5 192.168.1.10 192.168.1.11
22   RA          RA           RA
80   SA          RA           SA
443 SA          RA           SA

Con srloop enviamos un paquete para la capa 3 de forma cíclica e imprime una sola respuesta cada vez.

>>> srloop(IP(dst=»192.168.1.245″, ttl=64)/TCP(dport=80))
RECV 1: IP / TCP 192.168.1.245:www > 192.168.1.88:ftp_data RA / Padding
fail 1: IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S
fail 1: IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S
fail 1: IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S
fail 1: IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S
fail 1: IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S
fail 1: IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S
fail 1: IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S
fail 1: IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S
RECV 1: IP / TCP 192.168.1.245:www > 192.168.1.88:ftp_data RA / Padding
fail 1: IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S
fail 1: IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S
fail 1: IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S
fail 1: IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S
fail 1: IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S
fail 1: IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S
fail 1: IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S
fail 1: IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S
RECV 1: IP / TCP 192.168.1.245:www > 192.168.1.88:ftp_data RA / Padding
fail 1: IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S
send…
Sent 20 packets, received 3 packets. 15.0% hits.
(, )
>>> ans,unans=_
>>> ans.summary()
IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S ==> IP / TCP 192.168.1.245:www > 192.168.1.88:ftp_data RA / Padding
IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S ==> IP / TCP 192.168.1.245:www > 192.168.1.88:ftp_data RA / Padding
IP / TCP 192.168.1.88:ftp_data > 192.168.1.245:www S ==> IP / TCP 192.168.1.245:www > 192.168.1.88:ftp_data RA / Padding

================

Hasta aquí por hoy. Seguimos con el envio de paquetes en la parte 5 de esta serie.

Esta entrada fue publicada en Scapy, Seguridad y redes y etiquetada , , , , , , . Guarda el enlace permanente.

Una respuesta a Scapy. Manipulación avanzada e interactiva de paquetes. Parte 4

  1. Francisco. R. dijo:

    Grcias alfon por este gran artículo y todos los referidos a Scapy. Me fueron de mucha utilidad.

Deja un comentario