Performing a ping sweep with Scapy

One of the first tasks to perform when you have identified a target network is to check which hosts are live. A simple way of achieving this is to ping an IP address and confirm whether or not a reply is received. However, doing this for more than a few hosts can quickly become a draining task. This recipe aims to show you how you can achieve this with Scapy.

Scapy is a powerful tool that can be used to manipulate network packets. While we will not be going into great depth of all that can be accomplished with Scapy, we will use it in this recipe to determine which hosts reply to an Internet Control Message Protocol (ICMP) packet. While you can probably create a simple bash script and tie it together with some grep filtering, this recipe aims to show you techniques that will be useful for tasks involving iterating through IP ranges, as well as an example of basic Scapy usage.

Scapy can be installed on the majority of Linux systems with the following command:

$ sudo apt-get install python-scapy

How to do it…

The following script shows how you can use Scapy to create an ICMP packet to send and process the response if it is received:

import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)

import sys 
from scapy.all import *

if len(sys.argv) !=3:
    print "usage: %s start_ip_addr end_ip_addr" % (sys.argv[0])
    sys.exit(0)

livehosts=[]
#IP address validation
ipregex=re.compile("^([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0- 9]|25[0-5]).([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0- 5]).([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).([0- 9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$")

if (ipregex.match(sys.argv[1]) is None):
  print "Starting IP address is invalid"
  sys.exit(0)
if (ipregex.match(sys.argv[1]) is None):
  print "End IP address is invalid"
  sys.exit(0)

iplist1 = sys.argv[1].split(".")
iplist2 = sys.argv[2].split(".")

if not (iplist1[0]==iplist2[0] and iplist1[1]==iplist2[1] and iplist1[2]==iplist2[2])
  print "IP addresses are not in the same class C subnet"
  sys.exit(0)	

if iplist1[3]>iplist2[3]:
  print "Starting IP address is greater than ending IP address"
  sys.exit(0)

networkaddr = iplist1[0]+"."+iplist1[1]+"."+iplist[2]+"."

start_ip_last_octet = int(iplist1[3])
end_ip_last_octet = int(iplist2[3])

if iplist1[3]<iplist2[3]:
  print "Pinging range "+networkaddr+str(start_ip_last_octet)+"- "+str(end_ip_last_octet)
else
  print "Pinging "+networkaddr+str(startiplastoctect)+"
"

for x in range(start_ip_last_octet, end_ip_last_octet+1)
  packet=IP(dst=networkaddr+str(x))/ICMP()
  response = sr1(packet,timeout=2,verbose=0)
  if not (response is None):
    if  response[ICMP].type==0:
      livehosts.append(networkaddr+str(x))

print "Scan complete!
"
if len(livehosts)>0:
  print "Hosts found:
"
  for host in livehosts:
    print host+"
"
else:
  print "No live hosts found
"

How it works…

The first section of the script will set up suppression of warning messages from Scapy when it runs. A common occurrence when importing Scapy on machines that do not have IPv6 configured is a warning message about not being able to route through IPv6.

import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)

The next section imports the necessary modules, validates the number of arguments received, and sets up a list for storing hosts found to be live:

import sys 
from scapy.all import *

if len(sys.argv) !=3:
    print "usage: %s start_ip_addr end_ip_addr" % (sys.argv[0])
    sys.exit(0)

livehosts=[]

We then compile a regular expression that will check that the IP addresses are valid. This not only checks the format of the string, but also that it exists within the IPv4 address space. This compiled regular expression is then used to match against the supplied arguments:

#IP address validation
ipregex=re.compile("^([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0- 9]|25[0-5]).([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0- 5]).([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).([0- 9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$")

if (ipregex.match(sys.argv[1]) is None):
  print "Starting IP address is invalid"
  sys.exit(0)
if (ipregex.match(sys.argv[1]) is None):
  print "End IP address is invalid"
  sys.exit(0)

Once the IP addresses have been validated, then further checks are carried out to ensure that the range supplied is a valid range and to assign the variables that will be used to set the parameters for the loop:

iplist1 = sys.argv[1].split(".")
iplist2 = sys.argv[2].split(".")

if not (iplist1[0]==iplist2[0] and iplist1[1]==iplist2[1] and iplist1[2]==iplist2[2])
  print "IP addresses are not in the same class C subnet"
  sys.exit(0)

if iplist1[3]>iplist2[3]:
  print "Starting IP address is greater than ending IP address"
  sys.exit(0)

networkaddr = iplist1[0]+"."+iplist1[1]+"."+iplist[2]+"."

start_ip_last_octet = int(iplist1[3])
end_ip_last_octet = int(iplist2[3])

The next part of the script is purely informational and can be omitted. It will print out the IP address range to be pinged or, in the case of both arguments supplied being equal, the IP address to be pinged:

if iplist1[3]<iplist2[3]:
  print "Pinging range "+networkaddr+str(start_ip_last_octet)+"- "+str(end_ip_last_octet)
else
  print "Pinging "+networkaddr+str(startiplastoctect)+"
"

We then enter the loop and start by creating an ICMP packet:

for x in range(start_ip_last_octet, end_ip_last_octet+1)
  packet=IP(dst=networkaddr+str(x))/ICMP()

After that, we use the sr1 command to send the packet and receive one packet back:

response = sr1(packet,timeout=2,verbose=0)

Finally, we check that a response was received and that the response code was 0. The reason for this is because a response code of 0 represents an echo reply. Other codes may be reporting an inability to reach the destination. If a response passes these checks, then the IP address is appended to the livehosts list:

if not (response is None):
    if  response[ICMP].type==0:
      livehosts.append(networkaddr+str(x))

If live hosts have been found, then the script will then print out the list.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.237.123