My l3g3nd

There is no spoon

Scapy - Network Enumeration

| Comments

Scapy is a very powerful API that can be used to “easily handle most classical tasks like scanning, tracerouting, probing, unit tests, attacks or network discovery” and more can be read here. I have decided to put all together with the help of Python and create a program that can be used to enumerate any network.

This will obviously require some time so I have planned to complete the project in phases. In this initial commit I have created couple of modules that will do the ICMP ping and ARP ping.

ICMP Ping

Scapy provides the ability to fully construct a packet and send according to our need. Also, it gives the ability to send one packet with SR1 or multiple packets with SR. Lot of this is pretty self explanatory and going in the details of how scapy works is beyond the scope of this write up.

1
ans,unans=sr(IP(dst=192.168.1.10)/ICMP(), inter=0.05,timeout=0.5)

The send and receive functionality (SR or SR1) returns couple of two lists. “The first element is a list of couples (packet sent, answer), and the second element is the list of unanswered packets. These two elements are lists, but they are wrapped by an object to present them better, and to provide them with some methods that do most frequently needed actions” more can be read here.

Apart from doing the ICMP ping we can also identify type of machine based on the TTL values. I am using following default values as I have only these in my network and most network devices are running Linux:

1
2
TTL = 128 for Windows
TTL = 64 for Linux

Coming back to answer list from the SR, the answer list can be iterated in the following way to read the TTL (or any other information from the packet) to decide whether the machine is Linux or Windows.

1
2
3
4
5
for s,r in ans:
if r.ttl < 65:
      print "{0} is alive and is Linux(TTL = {1})".format(str(r.src), str(r.ttl))
  else:
      print "{0} is alive and is Windows(TTL = {1})".format(str(r.src), str(r.ttl))

I am making the assumption here that if the TTL is less that 65 then its Linux else a Windows machine. This can be modified as required. Putting all together the entire icmp_ping.py program looks like

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/python

import string, sys
from scapy.all import *

def icmpping(host):
  try:
      ans,unans=sr(IP(dst=host)/ICMP(), inter=0.05,timeout=0.5)
      for s,r in ans:
          
          if r.ttl < 65:
              print "{0} is alive and is Linux(TTL = {1})".format(str(r.src), str(r.ttl))
          else:
              print "{0} is alive and is Windows(TTL = {1})".format(str(r.src), str(r.ttl))    
  except Exception, e:
      print e

def main():
  icmpping(host)

if __name__ == '__main__':
  main()

ARP Ping

Similar to the ICMP ping ARP ping can be used as follows:

1
ans,unans=srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=192.168.1.10),timeout=2)

The answer list can be iterated to read the MAC address from the packet:

1
2
for s,r in ans:
  print "{0} is the MAC address for host {1}".format(r.src, r.psrc)

The entire arp_ping.py looks as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/python

import string, sys
from scapy.all import *

def arpping(host):
  try:
      ans,unans=srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=host),timeout=2)
      for s,r in ans:
          print "{0} is the MAC address for host {1}".format(r.src, r.psrc)
  except Exception, e:
      print e

def main():
  arpping(host)

if __name__ == '__main__':
  main()

Network Enumeration

I wrote the main program networkenum.py that will contain all the options for enumerating the network such as icmp ping, arp ping, port scanning, etc. I will be updating the main netowkrenum.py in future. For now networkenum.py looks like below where the above 2 scripts are called:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/python

import string, optparse, sys, icmp_ping, arp_ping
from scapy.all import *

def main():
  try:
      parser = optparse.OptionParser('usage: ' + sys.argv[0] + ' -H <target ip>')
      parser = optparse.OptionParser()
      parser.add_option('-H', dest='host', help='specify IP address or subnet like 192.168.1.1-100 for ICMP Ping')
      parser.add_option('-A', dest='host', help='specify IP address or subnet like 192.168.1.1-100 for Arping')     
      (options, args) = parser.parse_args()
      host=options.host
      if options.host !=None:
          if sys.argv[1] == "-H":
              icmp_ping.icmpping(host)
          if sys.argv[1] == "-A":        
              arp_ping.arpping(host)            
      else:
          print parser.usage
      
  except Exception, e:
      print e

if __name__ == '__main__':
  main()

The sample program and output will look like this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
root@kali:~/scapy# python network.py -h
WARNING: No route found for IPv6 destination :: (no default route?)
Usage: network.py [options]

Options:
  -h, --help  show this help message and exit
  -H HOST     specify IP address or subnet like 192.168.1.1-100 for ICMP Ping
  -A HOST     specify IP address or subnet like 192.168.1.1-100 for Arping

root@kali:~/scapy# python network.py -A 192.168.1.1-10
WARNING: No route found for IPv6 destination :: (no default route?)
Begin emission:
*Finished to send 10 packets.
***
Received 4 packets, got 4 answers, remaining 6 packets
e0:f8:47:0c:1b:aa is the MAC address for host 192.168.1.4
20:e5:2a:11:e7:ee is the MAC address for host 192.168.1.1
8c:3a:e3:94:8e:ac is the MAC address for host 192.168.1.2
00:a0:96:43:8c:8f is the MAC address for host 192.168.1.5

root@kali:~/scapy# python networkenum.py -H 192.168.1.1-10
WARNING: No route found for IPv6 destination :: (no default route?)
Begin emission:
.*...............*.*.................*........*...........................WARNING: Mac address to reach destination not found. Using broadcast.
.......................................WARNING: Mac address to reach destination not found. Using broadcast.
.................................WARNING: more Mac address to reach destination not found. Using broadcast.
..........................................WARNING: Mac address to reach destination not found. Using broadcast.
Finished to send 10 packets.
...........
Received 199 packets, got 5 answers, remaining 5 packets
192.168.1.1 is alive and is Linux(TTL = 64)
192.168.1.4 is alive and is Linux(TTL = 64)
192.168.1.5 is alive and is Linux(TTL = 64)
192.168.1.2 is alive and is Linux(TTL = 64)
192.168.1.3 is alive and is Linux(TTL = 64)

This program needs to be run with root privileges. Feel free to ask if you have any questions and I will add this to my git for further modifications.

Comments