Using ARPing to perform layer 2 discovery
ARPing is a command-line network utility that has a functionality that is similar to the commonly used ping utility. This tool can identify whether a live host is on a local network at a given IP by supplying that IP address as an argument. This recipe will discuss how to use ARPing to scan for live hosts on a network.
Getting ready
To use ARPing to perform ARP discovery, you will need to have at least one system on the LAN that will respond to ARP requests. In the examples provided, a combination of Linux and Windows systems are used. For more information on setting up systems in a local lab environment, please refer to the Installing Metasploitable2 and Installing Windows Server recipes in Chapter 1, Getting Started. Additionally, this section will require a script to be written to the filesystem, using a text editor such as VIM or Nano. For more information on writing scripts, please refer to the Using text editors (VIM and Nano) recipe in Chapter 1, Getting Started.
How to do it…
ARPing is a tool that can be used to send ARP requests and identify whether a host is alive and responding. The tool is used by simply passing an IP address as an argument to it:
root@KaliLinux:~# arping 172.16.36.135 -c 1 ARPING 172.16.36.135 60 bytes from 00:0c:29:3d:84:32 (172.16.36.135): index=0 time=249.000 usec --- 172.16.36.135 statistics --- 1 packets transmitted, 1 packets received, 0% unanswered (0 extra)
In the example provided, a single ARP request is sent to the broadcast address, requesting the physical location of the 172.16.36.135
IP address. As indicated by the output, a single reply was received by the host with the 00:0C:29:3D:84:32
MAC address. This tool can be more effectively used for layer 2 discovery, scanning if a bash script is used to perform this action on multiple hosts simultaneously. In order to test the responses of each instance in bash, we should determine a unique string that is included in the response, indicating a live host but not included when no response is received. To identify a unique string, an ARPing request should be made to a nonresponsive IP address:
root@KaliLinux:~# arping 172.16.36.136 -c 1 ARPING 172.16.36.136 --- 172.16.36.136 statistics --- 1 packets transmitted, 0 packets received, 100% unanswered (0 extra)
By analyzing varying responses from successful and unsuccessful ARPings, one might notice that the unique bytes from
string only exists in the response if there is a live host associated with the provided IP address, and it is also within a line that includes the IP address. By grepping at this response, we can extract the IP address for each responding host:
root@KaliLinux:~# arping -c 1 172.16.36.135 | grep "bytes from" 60 bytes from 00:0c:29:3d:84:32 (172.16.36.135): index=0 time=291.000 usec root@KaliLinux:~# arping -c 1 172.16.36.136 | grep "bytes from" root@KaliLinux:~#
Grepping for this unique string when performing an ARPing against an actual host IP returns a line with that IP address included, as seen in the first response from the previous set of commands. Performing the same task against an IP address that is not associated with an actual host returns nothing, as seen in the last response from the previous set of commands. Using cut
with a specially crafted delimiter (-d
) and the field (-f
) values, we can quickly extract the IP address from this string. The command-line function, cut
, can be used in bash to separate a line into an array based on a specified delimiter. A specific value can then be returned from the cut
function by specifying the field. By piping over the output multiple times, we can easily extract the MAC address from the returned string. Have a look at the following set of commands:
root@KaliLinux:~# arping -c 1 172.16.36.135 | grep "bytes from" 60 bytes from 00:0c:29:3d:84:32 (172.16.36.135): index=0 time=10.000 usec root@KaliLinux:~# arping -c 1 172.16.36.135 | grep "bytes from" | cut -d " " -f 4 00:0c:29:3d:84:32
We can easily extract the IP address from the returned string by merely manipulating the delimiter and field values supplied to the cut
function:
root@KaliLinux:~# arping -c 1 172.16.36.135 | grep "bytes from" 60 bytes from 00:0c:29:3d:84:32 (172.16.36.135): index=0 time=328.000 usec root@KaliLinux:~# arping -c 1 172.16.36.135 | grep "bytes from" | cut -d " " -f 5 (172.16.36.135): root@KaliLinux:~# arping -c 1 172.16.36.135 | grep "bytes from" | cut -d " " -f 5 | cut -d "(" -f 2 172.16.36.135): root@KaliLinux:~# arping -c 1 172.16.36.135 | grep "bytes from" | cut -d " " -f 5 | cut -d "(" -f 2 | cut -d ")" -f 1 172.16.36.135
Upon identifying how to extract the IP address from a positive ARPing response, we can easily pass this task through a loop in a bash script and output a list of live IP addresses. An example of a script that uses this technique is shown as follows:
#!/bin/bash if [ "$#" -ne 1 ]; then echo "Usage - ./arping.sh [interface]" echo "Example - ./arping.sh eth0" echo "Example will perform an ARP scan of the local subnet to which eth0 is assigned" exit fi interface=$1 prefix=$(ifconfig $interface | grep 'inet addr' | cut -d ':' -f 2 | cut -d ' ' -f 1 | cut -d '.' -f 1-3) for addr in $(seq 1 254); do arping -c 1 $prefix.$addr | grep "bytes from" | cut -d " " -f 5 | cut -d "(" -f 2 | cut -d ")" -f 1 & done
In the bash script that is provided, the first line defines the location of the bash interpreter. The block of code that follows performs a test to determine whether the expected argument was supplied. This is determined by evaluating if the number of supplied arguments is not equal to 1
. If the expected argument is not supplied, the usage of the script is output, and the script exits. The usage output indicates that the script is expecting the local interface name as an argument. The next block of code assigns the supplied argument to the interface
variable. The interface value is then supplied to ifconfig
, and the output is then used to extract the network prefix. For example, if the IP address of the supplied interface is 192.168.11.4
, the prefix
variable would be assigned 192.168.11
. A for
loop is then used to cycle through the values of the last octet to generate each possible IP address in the local /24
network. For each possible IP address, a single arping
command is issued. The response for each of these requests is then piped over, and then grep
is used to extract lines with the phrase, bytes from
. As discussed earlier, this will only extract lines that include the IP address of live hosts. Finally, a series of cut
functions are used to extract the IP address from this output. Notice that an ampersand is used at the end of the for
loop task instead of a semicolon. The ampersand allows the tasks to be performed in parallel instead of in sequence. This drastically reduces the amount of time required to scan the IP range. Have a look at the following set of commands:
root@KaliLinux:~# ./arping.sh Usage - ./arping.sh [interface] Example - ./arping.sh eth0 Example will perform an ARP scan of the local subnet to which eth0 is assigned root@KaliLinux:~# ./arping.sh eth0 172.16.36.1 172.16.36.2 172.16.36.132 172.16.36.135 172.16.36.254
One can easily redirect the output of the script to a text file that can then be used for subsequent analysis. The output can be redirected using the right-angled bracket, followed by the name of the text file. An example of this can be seen as follows:
root@KaliLinux:~# ./arping.sh eth0 > output.txt root@KaliLinux:~# ls output.txt output.txt root@KaliLinux:~# cat output.txt 172.16.36.1 172.16.36.2 172.16.36.132 172.16.36.135 172.16.36.254
Once the output has been redirected to the output file, you can use the ls
command to verify that the file was written to the filesystem, or you can use the cat
command to view the contents of the file. This script can also be modified to read from an input file and only verify that the hosts listed in this file are alive. For the following script, you will need an input file with a list of IP addresses. For this, we can use the same input file that was used for the Scapy script, discussed in the previous recipe:
#!/bin/bash if [ "$#" -ne 1 ]; then echo "Usage - ./arping.sh [input file]" echo "Example - ./arping.sh iplist.txt" echo "Example will perform an ARP scan of all IP addresses defined in iplist.txt" exit fi file=$1 for addr in $(cat $file); do arping -c 1 $addr | grep "bytes from" | cut -d " " -f 5 | cut -d "(" -f 2 | cut -d ")" -f 1 & done
The only major difference between this script and the preceding one is that rather than supplying an interface name, the filename of the input list is supplied upon the execution of the script. This argument is passed to the file
variable. The for
loop is then used to loop through each value in this file to perform the ARPing task. To execute the script, use a period and forward slash, followed by the name of the executable script:
root@KaliLinux:~# ./arping.sh Usage - ./arping.sh [input file] Example - ./arping.sh iplist.txt Example will perform an ARP scan of all IP addresses defined in iplist.txt root@KaliLinux:~# ./arping.sh iplist.txt 172.16.36.1 172.16.36.2 172.16.36.132 172.16.36.135 172.16.36.254
Executing the script without any arguments supplied will return the usage of the script. This usage indicates that an input file should be supplied as an argument. When this is done, the script is executed, and a list of live IP addresses is returned from the input list of IP addresses. In the same manner as discussed earlier, the output of this script can easily be redirected to an output file using the right-angled bracket. An example of this can be seen as follows:
root@KaliLinux:~# ./arping.sh iplist.txt > output.txt root@KaliLinux:~# ls output.txt output.txt root@KaliLinux:~# cat output.txt 172.16.36.1 172.16.36.2 172.16.36.132 172.16.36.135 172.16.36.254
Once the output has been redirected to the output file, you can use the ls
command to verify that the file was written to the filesystem, or you can use the cat
command to view the contents of the file.
How it works…
ARPing was a tool that was written with the intention of validating whether a single host is online. However, the simplicity of its use makes it easy to manipulate it in bash to scan multiple hosts in sequence. This is done by looping through a series of IP addresses, which are then supplied to the utility as arguments.