Layer 3 discovery - ICMP

In order to send an ICMP echo request using Scapy, we will need to start stacking layers to send requests. A good rule of thumb when stacking packets is to work up through the layers of the OSI model. You can stack multiple layers by separating each layer with a forward slash. To generate an ICMP echo request, an IP layer needs to be stacked with an ICMP request:

  1. To get started, use the scapy command to open the Scapy interactive console, and then assign an IP object to a variable:
  1. In the example provided, the display() function was used to view the default configurations of the object attributes after it was assigned to the ip variable. By default, the IP object is configured to send and receive using the loopback IP address of 127.0.0.1. To change any attribute of an object in Scapy, you need to set [object].[attribute] equal to the desired value. In this case, we want to change the destination IP address to the address of the system that we would like to send the ICMP request to, as shown in the following set of commands:
  1. After assigning the new value to the destination address attribute, the changes can be verified by calling the display() function once again. Notice that when the destination IP address value is changed to any other value, the source address is also automatically updated from the loopback address to the IP address associated with the default interface. Now that the attributes of the IP object have been appropriately modified, we will need to create the second layer in our packet stack. The next layer to be added to the stack is the ICMP layer, which we will assign to a separate variable:
  1. In the example provided, the ICMP object was initialized with the ping variable name. The display() function can then be called to display the default configurations of the ICMP attributes. To perform an ICMP echo request, the default configurations are sufficient. Now that both layers have been configured correctly, they can be stacked in preparation to send. In Scapy, layers can be stacked by separating each layer with a forward slash. Have a look at the following set of commands:
  1. Once the stacked layers have been assigned to a variable, the display() function will then show the entire stack. The process of stacking layers in this manner is often referred to as datagram encapsulation. Now that the layers have been stacked, the request is ready to be sent across the wire. This can be done using the sr1() function in Scapy:
  1. In the example provided, the sr1() function is assigned to the ping_reply variable. This executes the function and then passes the result to this variable. After receiving the response, the display() function is used on the ping_reply variable to see the contents of the response. Notice that this packet was sent from the host to which we sent the initial request, and the destination address is the IP address of our Kali system. Additionally, notice that the ICMP type of the response is an echo reply. This process of sending and receiving ICMP with Scapy may seem functional, based on this example, but if you attempt to use the same process with a non-responsive target address, you will quickly notice the problem:
  1. The example output was truncated, but this output will continue indefinitely until you force an escape with Ctrl + C. Without supplying a timeout value to the function, the sr1() function will continue to listen until a response is received. If a host is not alive or if the IP address is not associated with any host, no response will be sent, and the function will not exit. To use this function effectively within a script, a timeout value should be defined:
  1. By supplying a timeout value as a second argument passed to the sr1() function, the process will then exit if no response is received within the designated number of seconds. In the example provided, the sr1() function is used to send the ICMP request to a nonresponsive address that is exited after 1 second because no response was received. In the examples provided so far, we have assigned functions to variables to create objects that are persistent and can be manipulated. However, these functions do not have to be assigned to variables but can also be generated by calling the functions directly:
  1. In the example provided here, all of the work that was done earlier with four separate commands can actually be accomplished with a single command by directly calling the functions. Notice that if an ICMP request is sent to an IP address that does not reply within the timeframe specified by the timeout value, calling the object will result in an exception. As no response was received, the answer variable in this example that was set equal to the response is never initialized:
  1. Knowledge of these varied responses can be used to generate a script that will perform ICMP requests on multiple IP addresses in sequence. The script will loop through all of the possible values for the last octet in the destination IP address, and for each value, it will send an ICMP request. As each sr1() function is returned, the response is evaluated to determine whether an echo response was received:
        #!/usr/bin/python

import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *

if len(sys.argv) != 2:
print "Usage - ./pinger.py [/24 network address]"
print "Example - ./pinger.py 172.16.36.0"
print "Example will perform an ICMP scan of
the 172.16.36.0/24 range"
sys.exit()

address = str(sys.argv[1])
prefix = address.split('.')[0] + '.' + address.split('.')[1]
+ '.' +address.split('.')[2] + '.'

for addr in range(1,254):
answer=sr1(ARP(pdst=prefix+str(addr)),timeout=1,verbose=0)
if answer == None:
pass
else:
print prefix+str(addr)
  • The first line of the script indicates where the Python interpreter is located so that the script can be executed without it being passed to the interpreter. The script then imports all Scapy functions and also defines Scapy logging levels to eliminate unnecessary output in the script.
  • The second block of code is a conditional test that evaluates whether the required argument is supplied to the script. If the required argument is not supplied upon execution, the script will then output an explanation of appropriate script usage. This explanation includes the usage of the tool, an example, and an explanation of the task that will be performed by this example.
  • After this block of code, the supplied value is assigned to the address variable. That value is then used to extract the network prefix. For example, if the address variable contains the 192.168.11.0 string , the value of 192.168.11 will be assigned to the prefix variable.
  • The final block of code is a for loop that performs the actual scanning. The for loop cycles through all values between 0 and 254, and for each iteration, the value is then appended to the network prefix. In the case of the example provided earlier, an ICMP echo request would be sent to each IP address between 192.168.11.0 and 192.168.11.254. For each live host that does reply, the corresponding IP address is then printed to the screen to indicate that the host is alive on the LAN.
  1. Once the script has been written to the local directory, you can execute it in the Terminal using a period and forward slash, followed by the name of the executable script:
  1. If the script is executed without any arguments supplied, the usage is output to the screen. The usage output indicates that this script requires a single argument that defines the /24 network to scan. In the example provided, the script is executed using the 172.16.36.0 network address. The script then outputs a list of live IP addresses in the /24 network range. This output can also be redirected to an output text file using a greater-than sign followed by the output filename. An example of this is as follows:
  1. The ls command can then be used to verify that the output file was written to the filesystem, or the cat command can be used to view its contents. This script can also be modified to accept a list of IP addresses as input. To do this, the for loop must be changed to loop through the lines that are read from the specified text file. An example of this can be seen as follows:
        #!/usr/bin/python

import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *

if len(sys.argv) != 2:
print "Usage - ./pinger.py [filename]"
print "Example - ./pinger.py iplist.txt"
print "Example will perform an ICMP ping scan
of the IP addresses listed in iplist.txt"
sys.exit()

filename = str(sys.argv[1])
file = open(filename,'r')

for addr in file:
ans=sr1(IP(dst=addr.strip())/ICMP(),timeout=1,verbose=0)
if ans == None:
pass
else:
print addr.strip()
  1. The only major difference from the prior script is that this one accepts an input filename as an argument and then loops through each IP address listed in this file to scan. Similar to the other script, the resulting output will include a simple list of IP addresses associated with systems that responded to the ICMP echo request with an ICMP echo response:
  1. The output of this script can be redirected to an output file in the same way. Execute the script with the input file supplied as an argument and then redirect the output using a greater-than sign followed by the name of the output text file.  An example of this can be seen as follows:
..................Content has been hidden....................

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