Ferramentas do usuário

Ferramentas do site


dev:scapy:scapy_testes_rede

SCAPY - Testes de redes

Scapy é um software para manipulação de pacotes, ele pode montar pacotes para simular testes e envia-los pela rede. Isso é perfeito para testes de rede e troubleshooting. O Scapy roda encima da linguagem Python,

Para executar o Scapy digite apenas o comando scapy.

root@bumblee:~# scapy
INFO: Cant import matplotlib. Wont be able to plot.
INFO: Cant import PyX. Wont be able to use psdump() or pdfdump().
WARNING: No route found for IPv6 destination :: (no default route?)
INFO: Cant import python ecdsa lib. Disabled certificate manipulation tools
Welcome to Scapy (2.3.3)
>>>

O Scapy pode ser executado em dois modos: interativo, módulo ou script.

Scapy - Modo interativo

No modo interativo podemos executar comandos básicos

LSC

>>> lsc()
arpcachepoison      : Poison targets cache with (your MAC,victims IP) couple
arping              : Send ARP who-has requests to determine which hosts are up
bind_layers         : Bind 2 layers on some specific fields values
bridge_and_sniff    : Forward traffic between two interfaces and sniff packets exchanged
corrupt_bits        : Flip a given percentage or number of bits from a string
corrupt_bytes       : Corrupt a given percentage or number of bytes from a string
defrag              : defrag(plist) -> ([not fragmented], [defragmented],
defragment          : defrag(plist) -> plist defragmented as much as possible
dyndns_add          : Send a DNS add message to a nameserver for "name" to have a new "rdata"
dyndns_del          : Send a DNS delete message to a nameserver for "name"
etherleak           : Exploit Etherleak flaw
fletcher16_checkbytes:  Calculates the Fletcher-16 checkbytes returned as 2 byte binary-string.
fletcher16_checksum :  Calculates Fletcher-16 checksum of the given buffer.
fragment            : Fragment a big IP datagram
fuzz                : Transform a layer into a fuzzy layer by replacing some default values by random objects
getmacbyip          : Return MAC address corresponding to a given IP address
hexdiff             : Show differences between 2 binary strings
hexdump             : --
hexedit             : --
is_promisc          : Try to guess if target is in Promisc mode. The target is provided by its ip.
linehexdump         : --
ls                  : List  available layers, or infos on a given layer class or name
promiscping         : Send ARP who-has requests to determine which hosts are in promiscuous mode
rdpcap              : Read a pcap or pcapng file and return a packet list
send                : Send packets at layer 3
sendp               : Send packets at layer 2
sendpfast           : Send packets at layer 2 using tcpreplay for performance
sniff               : Sniff packets
split_layers        : Split 2 layers previously bound
sr                  : Send and receive packets at layer 3
sr1                 : Send packets at layer 3 and return only the first answer
srbt                : send and receive using a bluetooth socket
srbt1               : send and receive 1 packet using a bluetooth socket
srflood             : Flood and receive packets at layer 3
srloop              : Send a packet at layer 3 in loop and print the answer each time
srp                 : Send and receive packets at layer 2
srp1                : Send and receive packets at layer 2 and return only the first answer
srpflood            : Flood and receive packets at layer 2
srploop             : Send a packet at layer 2 in loop and print the answer each time
traceroute          : Instant TCP traceroute
tshark              : Sniff packets and print them calling pkt.show(), a bit like text wireshark
wireshark           : Run wireshark on a list of packets
wrpcap              : Write a list of packets to a pcap file
>>>

Todos os comando acima são utilizados para enviar pacotes, traceroute, sniffer, etc.

Comando sniff()

Vamos utilizar o comando sniff para coletar pacotes ICMP

>>> sniff(1, filter='icmp', prn=Packet.show)
###[ Ethernet ]###
  dst= 00:e0:4c:51:3c:82
  src= b0:25:aa:29:71:89
  type= IPv4
###[ IP ]###
     version= 4L
     ihl= 5L
     tos= 0x0
     len= 60
     id= 65316
     flags=
     frag= 0L
     ttl= 128
     proto= icmp
     chksum= 0xa4f4
     src= 192.168.10.173
     dst= 192.168.10.170
     \options\
###[ ICMP ]###
        type= echo-request
        code= 0
        chksum= 0x47a3
        id= 0x1
        seq= 0x5b8
###[ Raw ]###
           load= 'abcdefghijklmnopqrstuvwabcdefghi'
 
<Sniffed: TCP:0 UDP:0 ICMP:1 Other:0>
>>>
sniff(1, filter='icmp', prn=Packet.show)
  • sniff - Comando para snifar
  • 1 - Quantidade de pacotes que combinar com o parametro filter
  • filter='icmp' - O filtro e para combinar pacotes do protocolo ICMP
  • prn=Packet.show - Mostrar o pacote combinado

Quando você executar o comando sniff ele ficará esperando até surgir o pacote ICMP na placa rede. Isso pode ser gerado com um comando ping. Repare cada camada do pacote.

LS

O comando ls, mostra os protocolos suportados.

>>> ls()
AH         : <member 'name' of 'Packet' objects>
ARP        : <member 'name' of 'Packet' objects>
ASN1P_INTEGER : <member 'name' of 'Packet' objects>
ASN1P_OID  : <member 'name' of 'Packet' objects>
ASN1P_PRIVSEQ : <member 'name' of 'Packet' objects>
ASN1_Packet : <member 'name' of 'Packet' objects>
ATT_Error_Response : <member 'name' of 'Packet' objects>
ATT_Exchange_MTU_Request : <member 'name' of 'Packet' objects>
ATT_Exchange_MTU_Response : <member 'name' of 'Packet' objects>
ATT_Find_By_Type_Value_Request : <member 'name' of 'Packet' objects>
ATT_Find_By_Type_Value_Response : <member 'name' of 'Packet' objects>
ATT_Find_Information_Request : <member 'name' of 'Packet' objects>
ATT_Find_Information_Response : <member 'name' of 'Packet' objects>
ATT_Handle_Value_Notification : <member 'name' of 'Packet' objects>
ATT_Hdr    : <member 'name' of 'Packet' objects>
ATT_Read_By_Group_Type_Request : <member 'name' of 'Packet' objects>
ATT_Read_By_Group_Type_Response : <member 'name' of 'Packet' objects>
.....

Mostra as informações do payload IP e TCP.

>>> ls(IP)
version    : BitField (4 bits)                   = (4)
ihl        : BitField (4 bits)                   = (None)
tos        : XByteField                          = (0)
len        : ShortField                          = (None)
id         : ShortField                          = (1)
flags      : FlagsField (3 bits)                 = (0)
frag       : BitField (13 bits)                  = (0)
ttl        : ByteField                           = (64)
proto      : ByteEnumField                       = (0)
chksum     : XShortField                         = (None)
src        : SourceIPField (Emph)                = (None)
dst        : DestIPField (Emph)                  = (None)
options    : PacketListField                     = ([])
>>> ls(TCP)
sport      : ShortEnumField                      = (20)
dport      : ShortEnumField                      = (80)
seq        : IntField                            = (0)
ack        : IntField                            = (0)
dataofs    : BitField (4 bits)                   = (None)
reserved   : BitField (3 bits)                   = (0)
flags      : FlagsField (9 bits)                 = (2)
window     : ShortField                          = (8192)
chksum     : XShortField                         = (None)
urgptr     : ShortField                          = (0)
options    : TCPOptionsField                     = ({})
>>>

Método summary

Todo o Scapy e orientado ao objeto, com isso temos métodos um dos métodos que é um dos mais importante é o método summary. O método nos da uma versão resumida do pacote.

>>> pkts = sniff(count=2, filter='icmp')
>>> pkts.summary()
Ether / IP / ICMP 192.168.10.173 > 192.168.10.170 echo-request 0 / Raw
Ether / IP / ICMP 192.168.10.170 > 192.168.10.173 echo-reply 0 / Raw
>>>

Método show e show2

O método show permite visualizar campos especificos do pacote.

>>> pkts[0].show()
###[ Ethernet ]###
  dst= 00:e0:4c:51:3c:82
  src= b0:25:aa:29:71:89
  type= IPv4
###[ IP ]###
     version= 4L
     ihl= 5L
     tos= 0x0
     len= 60
     id= 47392
     flags=
     frag= 0L
     ttl= 128
     proto= icmp
     chksum= 0xeaf8
     src= 192.168.10.173
     dst= 192.168.10.170
     \options\
###[ ICMP ]###
        type= echo-request
        code= 0
        chksum= 0x4793
        id= 0x1
        seq= 0x5c8
###[ Raw ]###
           load= 'abcdefghijklmnopqrstuvwabcdefghi'
 
>>> pkts[1].show()
###[ Ethernet ]###
  dst= b0:25:aa:29:71:89
  src= 00:e0:4c:51:3c:82
  type= IPv4
###[ IP ]###
     version= 4L
     ihl= 5L
     tos= 0x0
     len= 60
     id= 2778
     flags=
     frag= 0L
     ttl= 64
     proto= icmp
     chksum= 0xd93f
     src= 192.168.10.170
     dst= 192.168.10.173
     \options\
###[ ICMP ]###
        type= echo-reply
        code= 0
        chksum= 0x4f93
        id= 0x1
        seq= 0x5c8
###[ Raw ]###
           load= 'abcdefghijklmnopqrstuvwabcdefghi'
 
>>>

A diferença do método show2 para o método show é que alguns campos são calculados apenas quando o pacote é enviado para a rede. Então o método show2 permite ver estes campos calculados.

Comando wrpcap e rdpcap

Com o Scapy é possível capturar pacotes e salvar em um arquivo pcap para ser analisado posteriormente.

>>> pkts
<Sniffed: TCP:0 UDP:0 ICMP:2 Other:0>
>>> pkts.summary()
Ether / IP / ICMP 192.168.10.173 > 192.168.10.170 echo-request 0 / Raw
Ether / IP / ICMP 192.168.10.170 > 192.168.10.173 echo-reply 0 / Raw
>>> wrpcap('captura_icmp.pcap', pkts, sync=True)
>>> rdpcap('captura_icmp.pcap')
<captura_icmp.pcap: TCP:0 UDP:0 ICMP:2 Other:0>
>>>

Criando pacotes

Vamos criar um pacotes mas é possível coletar um pacote e mostrar os comandos para recria-lós. Por exemplo a variavel pkts capturado anteriormente podemos ver os comandos para recriar o pacote.

>>> pkts[0].command()
"Ether(src='b0:25:aa:29:71:89', dst='00:e0:4c:51:3c:82', type=2048)/IP(frag=0L, src='192.168.10.173', proto=1, tos=0, dst='192.168.10.170', chksum=60152, len=60, options=[], version=4L, flags=0L, ihl=5L, ttl=128, id=47392)/ICMP(gw=None, code=0, ts_ori=None, addr_mask=None, seq=1480, nexthopmtu=None, ptr=None, unused=None, ts_rx=None, length=None, chksum=18323, reserved=None, ts_tx=None, type=8, id=1)/Raw(load='abcdefghijklmnopqrstuvwabcdefghi')"
>>>
>>>
>>>
>>>
>>> icmp=Ether(src='b0:25:aa:29:71:89', dst='00:e0:4c:51:3c:82', type=2048)/IP(frag=0L, src='192.168.10.173', proto=1, tos=0, dst='192.168.10.170', chksum=60152, len=60, options=[], version=4L, flags=0L, ihl=5L, ttl=128, id=47392)/ICMP(gw=None, code=0, ts_ori=None, addr_mask=None, seq=1480, nexthopmtu=None, ptr=None, unused=None, ts_rx=None, length=None, chksum=18323, reserved=None, ts_tx=None, type=8, id=1)/Raw(load='abcdefghijklmnopqrstuvwabcdefghi')
>>> icmp.show()
###[ Ethernet ]###
  dst= 00:e0:4c:51:3c:82
  src= b0:25:aa:29:71:89
  type= IPv4
###[ IP ]###
     version= 4L
     ihl= 5L
     tos= 0x0
     len= 60
     id= 47392
     flags=
     frag= 0L
     ttl= 128
     proto= icmp
     chksum= 0xeaf8
     src= 192.168.10.173
     dst= 192.168.10.170
     \options\
###[ ICMP ]###
        type= echo-request
        code= 0
        chksum= 0x4793
        id= 0x1
        seq= 0x5c8
###[ Raw ]###
           load= 'abcdefghijklmnopqrstuvwabcdefghi'
 
>>>

Vamos criar um pacote do tipo TCP com o nome da variavel tcp.

>>> tcp = IP() / TCP()
>>> tcp.show2()
###[ IP ]###
  version= 4L
  ihl= 5L
  tos= 0x0
  len= 40
  id= 1
  flags=
  frag= 0L
  ttl= 64
  proto= tcp
  chksum= 0x7ccd
  src= 127.0.0.1
  dst= 127.0.0.1
  \options\
###[ TCP ]###
     sport= ftp_data
     dport= http
     seq= 0
     ack= 0
     dataofs= 5L
     reserved= 0L
     flags= S
     window= 8192
     chksum= 0x917c
     urgptr= 0
     options= {}
 
>>>

É possivel gerar alguns valores aleatorios.

tcp[TCP].seq = RandInt()

Enviando pacotes

Para enviar pacotes utilizamos os comandos

  • send - Envia o pacote na camada 3.
  • sendp - Envia o pacote na camada 2.
  • sr - Envia e recebe pacotes na camada 3.
  • sr1 - Envia e recebe pacotes na camada 3 e retorna apenas o primeiro pacote.

Possue outros comandos, utilize o comando lsc() para verificar.

Exemplo de pacote na porta de destino 500 udp

udp = Ether()/IP()/UDP()
udp[Ether].dst = "00:1a:3f:79:f2:37"
udp[Ether].src = "00:e0:4c:51:3c:82"
udp[IP].dst =  "192.168.10.173"
udp[IP].src = "192.168.10.170"
udp[UDP].sport = 1000
udp[UDP].dport = 500

Recebendo pacotes

A função para receber os pacotes utilize o comando srp().

 

Mais exemplos https://thepacketgeek.com/scapy-p-04-looking-at-packets/