Этим я открываю небольшую серию по итогам презентации на тему "Анализ сетевых пакетов" от автора "CE 340/S. Kondakci, IEU, Computer Engineering". По ходу будет масса примеров анализа с помощью таких инструментов как Scapy, Nmap, Nping и tcpdump. Устраивайтесь поудобнее и начнем. А начнем мы со Scapy.
Scapy packet manipulation agenda:
- Creating a packet
- Send/Receiving packets
- Basic Scapy commands
- Capturing packets and reading packet capture files into Scapy
- Layering packets
Four steps before:
1. Install Python 3.5+
2. Download and install Scapy
3. Install additional software for special features (optional)
4. Run Scapy with root privileges.
Example: Hello World
send(IP(dst= 127.0.0.1 )/ICMP()/ HelloWorld )
- send - this tells Scapy that you want to send a packet (just a single packet)
- IP - the protocol of the packet you want to create
- (dst= 127.0.0.1 ) - the destination IP to send the packet to
- /ICMP() - Create an ICMP packet with the default values provided by Scapy
- / HelloWorld - the payload to include in the ICMP packet
Wireshark capture:
Scapy command: send(IP(dst= 127.0.0.1 )/ICMP()/ HelloWorld )
Wireshark output:
Internet Protocol Version 4, Src: 127.0.0.12 (127.0.0.12), Dst: 127.0.0.1 (127.0.0.1)
Protocol: ICMP
Data: 48656c6c6f576f726c64 or HelloWorld
Example: fabricate an ICMP Packet
send(IP(src= 127.0.0.1 , dst= 127.0.0.1 , ttl=128)/ICMP()/ HelloWorld )
Wireshark:
Internet Protocol Version 4, Src: 127.0.0.1 (127.0.0.1), Dst: 127.0.0.1 (127.0.0.1) Time to live: 128
What does this ICMP packet mean?
Internet Protocol Version 4, Src: 127.0.0.1 (127.0.0.1), Dst: 127.0.0.1 (127.0.0.1) Internet Control Message Protocol
Type: 0 (Echo (ping) reply)
Sending a ping packet:
ip=IP() # Creates an IP headerip.src=’192.168.1.25? # Source address in the IP header with local IP ip.dst =’ 192.168.1.100? # Destination address in the IP header.icmp=ICMP() # Creates an ICMP headericmp.type=8 # Type value inserted in ICMP header as 8 for ping icmp.code=0 # Code value inserted in ICMP header as 0 for pingsend(ip/icmp) # Sending ping packet.
Sending a ping packet with random source IP:
ip=IP() # Creates an IP headerip.src=RandIP() # The source address in the IP header with a random IP ip.dst =’ 192.168.1.100? # Destination address in the IP header.icmp=ICMP() # Creates an ICMP headericmp.type=8 # Type value inserted in ICMP header as 8 for ping craftingicmp.code=0 # Code value inserted in ICMP header as 0 for ping crafting.send(ip/icmp) # Sending ping packet.
Sending & receiving Layer 3 and 2 packets:
• sr() – This function sends packets and receives answers. It returns a couple of packet and answers, and the unanswered packets.
• sr1() - This function is a variant that only returns one packet which answered the sent packet sent.
• Exp: Simple ICMP packet (layer 3)
h=sr1(IP(dst= 127.0.0.1 )/ICMP()/ Hello World )
• srp() - This function does the same for layer 2 packets (Ethernet, 802.3, etc).
Show the packet contents:
• h=sr1(IP(dst= 127.0.0.1 )/ICMP()/ Hello World )
• h.show()
###[ IP ]###
version= 4L
ihl= 5L
tos= 0x0
len= 38
id= 7395
flags=
frag= 0L
ttl= 64
proto= icmp
chksum= 0x83d7
src= 127.0.0.1
dst= 127.0.0.1
\options\
###[ ICMP ]###
type= echo-reply
code= 0
chksum= 0x0
id= 0x0
seq= 0x0
###[ Raw ]###
load= 'HelloWorld'
###[ Padding ]###
load= '\x00\x00\x00\x00\xe7\x03N\x99'
>>>
Show the TTL of the ICMP reply packet:
ip=IP() # Create an IP header
ip.src=’192.168.1.25? # Source address in the IP header is the loca IP
ip.dst =’ 192.168.1.100? # Destination address in the IP header.
icmp=ICMP() # Create an ICMP header
icmp.type=8 # Type value inserted in ICMP header as 8 for ping crafting
icmp.code=0 # Code value inserted in ICMP header as 0 for ping crafting.
p=sr1(ip/icmp) # Send and receive the packet in the variable p
p.ttl # Displays the TTL value in the received IP header of the packet.
Create an ARP request:
ether=Ether() # Creates an ethernet header
ether.src=’00:e0:1c:3c:22:b4? # Source MAC address in the ethernet header
ether.dst=’FF:FF:FF:FF:FF:FF’ # Destination MAC address
arp=ARP() # Create an ARP header
arp.op=1 # Set the ARP type as 1
arp.hwsrc=’00:e0:1c:3c:22:b4? # Set the sender MAC address for local IP
arp.psrc=’192.168.1.25? # Set the sender IP address for that MAC addr.
arp.pdst=’192.168.1.100? # Set the target IP address
arp.hwdst=’00:00:00:00:00:00? # Set the target MAC address as NULL
p=srp1(ether/arp) # Send the packet at layer 2 using the command srp1, appending the ether and arp headers.
UDP Scanning:
- No handshake, so less useful than TCP scans
- Much more powerful in newer versions of Nmap
- Sends valid UDP requests to well-known ports
- Send a DNS query to port 53, etc.
- Response indicates open UDP port
TCP Packets:
p=sr(IP(dst= 127.0.0.1 )/TCP(dport=23))
Begin emission:
.Finished to send 1 packets.
*
Received 2 packets, got 1 answers, remaining 0 packets
>>> p
(<Results: TCP:1 UDP:0 ICMP:0 Other:0>, <Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>)
>>>
If you try and use p.show() you now get an error message:
>>> p.show()
Traceback (most recent call last):
File <console> , line 1, in <module>
AttributeError: 'tuple' object has no attribute 'show'
>>> ans.summary()
IP / TCP 127.0.0.1:ftp_data > 127.0.0.1:telnet S ==> IP / TCP 127.0.0.1:telnet > 127.0.0.1:ftp_data
RA / Padding
a=sr(IP(dst= 127.0.0.1 )/TCP(dport=[23,80,53]))
Begin emission:
.**Finished to send 3 packets.
*
Received 4 packets, got 3 answers, remaining 0 packets
>>> a
(<Results: TCP:3 UDP:0 ICMP:0 Other:0>, <Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>)
>>>
TCP SYN to port 80:
tcp=TCP() # Create a TCP headertcp.dport=80 # The destination port in the TCP header is 80.tcp.flags=’S’ # Set the flag in the TCP header with the SYN bit.ip=IP() # Create an IP headerip.src=’192.168.1.25? # Source address in the IP header is local IP address ip.dst =’ 192.168.1.100? # Destination address in the IP header.
send(ip/tcp) # Send the crafted tcp packet.
Details of the TCP packet:
>>> p
(<Results: TCP:3 UDP:0 ICMP:0 Other:0>, <Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>)
>>>
>>> ans,unans=_
>>> ans.summary()
IP / TCP 127.0.0.1:ftp_data > 127.0.0.1:telnet S ==> IP / TCP 127.0.0.1:telnet > 127.0.0.1:ftp_data
RA / Padding
IP / TCP 127.0.0.1:ftp_data > 127.0.0.1:http S ==> IP / TCP 127.0.0.1:http > 127.0.0.1:ftp_data SA /
Padding
IP / TCP 127.0.0.1:ftp_data > 127.0.0.1:domain S ==> IP / TCP 127.0.0.1:domain >
127.0.0.1:ftp_data SA / Padding
>>>
The http (port 80) packet:
IP / TCP 127.0.0.15:ftp_data > 127.0.0.1:http S ==> IP / TCP 127.0.0.1:http > 127.0.0.15:ftp_data SA /
Padding
S = SYN from client (request from the client))
SA = SYN-ACK from the server (reply from the server)
The telnet (port 23) Packet:
IP / TCP 127.0.0.1:ftp_data > 127.0.0.1:telnet S ==> IP / TCP 127.0.0.1:telnet > 127.0.0.1:ftp_data RA / Padding
SYN Sent from the source
Destination responded with a RSTACK (RA) which is a RESet & ACKnowledge flag in the TCP packet telling the source to reset the connection
Port Scan (TCP-SYN Scan):
a=sr(IP(dst= 127.0.0.1 )/TCP(sport=666,dport=[22,80,21,443], flags= S ))
Source port=666
Destination ports: 22,80,21,and 443
flags= S = SYN scan
>>> p=sr(IP(dst= 127.0.0.1 )/TCP(sport=666,dport=[22,80,21,443], flags= S ))
Begin emission:
***Finished to send 4 packets.
*
Received 4 packets, got 4 answers, remaining 0 packets
>>> p
(<Results: TCP:4 UDP:0 ICMP:0 Other:0>, <Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>)
>>> ans,unans=_
>>> ans.summary()
IP / TCP 127.0.0.15:666 > 127.0.0.1:ssh S ==> IP / TCP 127.0.0.1:ssh > 127.0.0.15:666 SA / Padding
IP / TCP 127.0.0.15:666 > 127.0.0.1:http S ==> IP / TCP 127.0.0.1:http > 127.0.0.15:666 SA / Padding
IP / TCP 127.0.0.15:666 > 127.0.0.1:ftp S ==> IP / TCP 127.0.0.1:ftp > 127.0.0.15:666 RA / Padding
IP / TCP 127.0.0.15:666 > 127.0.0.1:https S ==> IP / TCP 127.0.0.1:https > 127.0.0.15:666 RA /
Padding
>>>
TCP ACK flag sent after SYN flag:
>>> p=sr(IP(dst= 127.0.0.1 )/TCP(sport=888,dport=[21,22,80,443], flags= A ))
Begin emission:
.***Finished to send 4 packets.
*
Received 5 packets, got 4 answers, remaining 0 packets
>>> p
(<Results: TCP:4 UDP:0 ICMP:0 Other:0>, <Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>)
>>> ans,unans=_
>>> ans.summary()
IP / TCP 127.0.0.15:888 > 127.0.0.1:ftp A ==> IP / TCP 127.0.0.1:ftp > 127.0.0.15:888 R / Padding
IP / TCP 127.0.0.15:888 > 127.0.0.1:ssh A ==> IP / TCP 127.0.0.1:ssh > 127.0.0.15:888 R / Padding
IP / TCP 127.0.0.15:888 > 127.0.0.1:http A ==> IP / TCP 127.0.0.1:http > 127.0.0.15:888 R / Padding
IP / TCP 127.0.0.15:888 > 127.0.0.1:https A ==> IP / TCP 127.0.0.1:https > 127.0.0.15:888 R / Padding
>>>
Notice:
• the A (ACK) flag on the sent packet, with a R (RST) flag on the response, why?
• Because we sent a packet that it's only supposed to receive after a SYN-ACK packet and so it's reset by the destination.
DNS Query:
sr1(IP(dst= 127.0.0.1 )/UDP()/DNS(rd=1,qd=DNSQR(qname= www.ieu.edu.tr )))
dst=27.0.0.1 = destionation IP (DNS server)
/UDP() = DNS uses UDP protocol
/DNS = This is a DNS packet
rd=1 = Telling Scapy that recursion is desired
qd=DNSQR(qname= www.ieu.edu.tr ) = Get the DNS info about www.ieu.edu.tr
Traceroute:
traceroute ([ www.google.com ], maxttl=20)
Begin emission:
..*Finished to send 20 packets.
*****************
Received 20 packets, got 18 answers, remaining 2 packets
74.125.132.99:tcp80
1 172.1.16.2 11
3 80.3.129.161 11
4 212.43.163.221 11
5 62.252.192.157 11
6 62.253.187.178 11
17 74.125.132.99 SA
18 74.125.132.99 SA
19 74.125.132.99 SA
20 74.125.132.99 SA
(<Traceroute: TCP:7 UDP:0 ICMP:11 Other:0>, <Unanswered: TCP:2 UDP:0 ICMP:0 Other:0>)
>>>
ARP scan on A network:
>>> arping( 172.1.16.* )
***Finished to send 256 packets.
*
Received 4 packets, got 4 answers, remaining 252 packets
30:46:9a:83:ab:70 172.1.16.2
00:25:64:8b:ed:1a 172.1.16.18
00:26:55:00:fc:fe 172.1.16.12
d8:9e:3f:b1:29:9b 172.1.16.22
(<ARPing: TCP:0 UDP:0 ICMP:0 Other:4>, <Unanswered: TCP:0 UDP:0 ICMP:0 Other:252>)
ICMP, TCP, and UDP Ping:
ans,unans=sr(IP(dst= 172.1.1-254 )/ICMP())
ans,unans=sr( IP(dst= 172.1.1.* )/TCP(dport=80, flags= S ) )
ans,unans=sr( IP(dst= 172.1.1.* /UDP(dport=0) )
Packet Sniffing:
sniff()
CTRL-C (to stop sniffing) get something like
<Sniffed: TCP:43 UDP:24 ICMP:2 Other:0>
a=_
a.nsummary()
0003 Ether / IP / UDP / DNS Qry daisy.ubuntu.com.
0004 Ether / IP / UDP / DNS Qry daisy.ubuntu.com.
0005 Ether / IP / UDP / DNS Qry daisy.ubuntu.com.
0006 Ether / IP / UDP / DNS Qry daisy.ubuntu.com.
0007 Ether / IP / UDP / DNS Qry daisy.ubuntu.com.
0008 Ether / IP / UDP / DNS Ans 91.189.95.54
0009 Ether / IP / UDP / DNS Ans 91.189.95.54
0010 Ether / IP / UDP / DNS Ans 91.189.95.54
0011 Ether / IP / UDP / DNS Ans 91.189.95.55
ICMP traffic through eth0 interface:
sniff(iface= eth0 , filter= icmp , count=10)
a=_
>>> a.nsummary()
0000 Ether / IP / ICMP / IPerror / UDPerror / DNS Ans 91.189.95.55
0001 Ether / IP / ICMP / IPerror / UDPerror / DNS Ans 91.189.95.54
0002 Ether / IP / ICMP 10.1.99.25 > 74.125.132.103 echo-request 0 / Raw
0003 Ether / IP / ICMP 74.125.132.103 > 10.1.99.25 echo-reply 0 / Raw
0004 Ether / IP / ICMP 10.1.99.25 > 74.125.132.103 echo-request 0 / Raw
0005 Ether / IP / ICMP 74.125.132.103 > 10.1.99.25 echo-reply 0 / Raw
0006 Ether / IP / ICMP 10.1.99.25 > 74.125.132.103 echo-request 0 / Raw
0007 Ether / IP / ICMP 74.125.132.103 > 10.1.99.25 echo-reply 0 / Raw
0008 Ether / IP / ICMP / IPerror / UDPerror / DNS Ans wb-in-f103.1e100.net.
0009 Ether / IP / ICMP / IPerror / UDPerror / DNS Ans wb-in-f103.1e100.net.
a[2]
<Ether dst=30:46:9a:83:ab:70 src=00:22:19:e7:90:ae type=0x800 |<IP version=4L ihl=5L tos=0x0
len=84 id=0 flags=DF frag=0L ttl=64 proto=icmp chksum=0xfeaa src=10.1.99.25 dst=74.125.132.103
Writing a Python Script:
Pcap file from tcpdump:
Script output:
No comments:
Post a Comment
А что вы думаете по этому поводу?