So today I’ve been playing with python and decided to make an arp ping utility. When i get more time i’ll turn this into a simple arp scanner.

I know that this is all possible using scapy but the idea of this was to teach myself how raw sockets work within python.

This requires netifaces and a few other modules that can usually be obtained using sudo easy_install modulename (you’ll require python-dev as well)

This script requires that you run as root in order to send and capture raw packets

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/usr/bin/env python
"""
Author:     phillips321 contact at phillips321.co.uk
License:    CC BY-SA 3.0
Use:        Simple python arp ping
Released:   www.phillips321.co.uk
Dependencies:
    netifaces (needs python-dev then easy_install netifaces)
ChangeLog:
    v0.2 - fixed response to search for target ip
    v0.1 - first release
"""

version = "0.2"
import socket
import struct
import sys
import netifaces
import binascii
if len(sys.argv) == 3 :
    target = sys.argv[1]
    interface = sys.argv[2]
elif len(sys.argv) == 2:
    target = sys.argv[1]
    interface = "eth0"
    print "No interface given so defaulting to eth0"
else: #no values defined print help
    print "Usage: %s IP [interface] \n   eg: %s 192.168.1.0 eth0" % (sys.argv[0],sys.argv[0])
    exit(1)

networkdetails = netifaces.ifaddresses(interface)
ipaddress = networkdetails[2][0]['addr']
macaddress = networkdetails[17][0]['addr']
print "Attempting to arp ping %s from %s using %s" % (target,ipaddress,macaddress)

# create packet
eth_hdr = struct.pack("!6s6s2s", '\xff\xff\xff\xff\xff\xff', macaddress.replace(':','').decode('hex'), '\x08\x06')             
arp_hdr = struct.pack("!2s2s1s1s2s", '\x00\x01', '\x08\x00', '\x06', '\x04', '\x00\x01')          
arp_sender = struct.pack("!6s4s", macaddress.replace(':','').decode('hex'), socket.inet_aton(ipaddress))
arp_target = struct.pack("!6s4s", '\x00\x00\x00\x00\x00\x00', socket.inet_aton(target))

count = 5
while count != 0:
    count = count - 1
    try:
        # send packet
        rawSocket = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.htons(0x0806))
        rawSocket.bind((interface, socket.htons(0x0806)))
        rawSocket.send(eth_hdr + arp_hdr + arp_sender + arp_target)
       
        # wait for response
        rawSocket = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.htons(0x0806))
        rawSocket.settimeout(0.5)
        response = rawSocket.recvfrom(2048)
        if target == socket.inet_ntoa(response[0][28:32]):
            print "Response from the folloiwing mac " + binascii.hexlify(response[0][6:12]).swapcase()
            break
        continue
    except socket.timeout:
        print "Attempt number %i did not get a response" % (count + 1)
        continue

2 Responses to Python arp ping code

  • phillips321 says:

    Or using scapy:

    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
    36
    37
    #!/usr/bin/env python
    """
    Author:     phillips321 contact at phillips321.co.uk
    License:    CC BY-SA 3.0
    Use:        Simple scapy arpscanner
    Released:   www.phillips321.co.uk
    Dependencies:
        scapy
    ChangeLog:
        v0.2 - first release
    """

    version = "0.2"
    import sys, netifaces, thread
    from scapy.all import *
    if len(sys.argv) == 2 :
        interface = sys.argv[1]
    else: #no values defined print help
        print "Usage: %s [interface] \n   eg: %s eth0" % (sys.argv[0],sys.argv[0])
        exit(1)

    sourceipaddress = netifaces.ifaddresses(interface)[2][0]['addr']
    netmask = netifaces.ifaddresses(interface)[2][0]['netmask']

    starttime = time.time()
    answered,unanswered=srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="192.168.0.0/24"), timeout=2, verbose=0)
    endtime = time.time()

    totaltime = endtime - starttime
    print "Sent ARP requests in %f seconds..." % (totaltime)

    for i in range(0,len(answered)):
        print "Response from " + answered[i][1].psrc + " using " + answered[i][1].hwsrc
       

    completedtime = time.time()
    totaltime = completedtime - starttime
    print "Completed scan in %f seconds..." % (totaltime)

    http://pastie.org/4337518

  • phillips321 says:

    meh, i had time after training to write a quick arpscanner using python:

    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    #!/usr/bin/env python
    """
    Author:     phillips321 contact at phillips321.co.uk
    License:    CC BY-SA 3.0
    Use:        Simple python arpscanner
    Released:   www.phillips321.co.uk
    Dependencies:
        netifaces (needs python-dev then easy_install netifaces)
    ChangeLog:
        v0.1 - first release
    """

    version = "0.1"
    import socket, struct, sys, netifaces, binascii, thread, time
    if len(sys.argv) == 2 :
        interface = sys.argv[1]
    else: #no values defined print help
        print "Usage: %s [interface] \n   eg: %s eth0" % (sys.argv[0],sys.argv[0])
        exit(1)

    networkdetails = netifaces.ifaddresses(interface)
    sourceipaddress = networkdetails[2][0]['addr']
    sourcemacaddress = networkdetails[17][0]['addr']

    def worker_thread(target, sourceipaddress, sourcemacaddress):
        # create packet
        eth_hdr = struct.pack("!6s6s2s", '\xff\xff\xff\xff\xff\xff', sourcemacaddress.replace(':','').decode('hex'), '\x08\x06')               
        arp_hdr = struct.pack("!2s2s1s1s2s", '\x00\x01', '\x08\x00', '\x06', '\x04', '\x00\x01')          
        arp_sender = struct.pack("!6s4s", sourcemacaddress.replace(':','').decode('hex'), socket.inet_aton(sourceipaddress))
        arp_target = struct.pack("!6s4s", '\x00\x00\x00\x00\x00\x00', socket.inet_aton(target))
        try:
            # send packet
            rawSocket = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.htons(0x0806))
            rawSocket.bind((interface, socket.htons(0x0806)))
            rawSocket.send(eth_hdr + arp_hdr + arp_sender + arp_target)
           
            # wait for response
            rawSocket = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.htons(0x0806))
            rawSocket.settimeout(0.5)
            response = rawSocket.recvfrom(2048)
            responseMACraw = binascii.hexlify(response[0][6:12])
            responseMAC = ":".join(responseMACraw[x:x+2] for x in xrange(0, len(responseMACraw), 2))
            responseIP = socket.inet_ntoa(response[0][28:32])
            if target == responseIP:
                print "Response from the mac %s on IP %s" % (responseMAC, responseIP)
        except socket.timeout:
            time.sleep(1)
           
    for i in range(256):
        target = "192.168.0." + str(i)
        thread.start_new_thread(worker_thread, (target, sourceipaddress, sourcemacaddress))
        time.sleep(0.2)

    download from here: http://pastie.org/4326656

Leave a Reply