Skip to content

Posts tagged ‘firewall’

26
Feb

Using ARP poisoning to Create an Ad-Hoc Firewall – Part 2: The Implementation

In the previous post I talked about how I intend to use ARP poisoning for creating an ad-hoc firewall. In this post I’ll try and implement this idea by using libcyanid which I also mentioned in the previous post. libcyanid provides functionality for injecting and sniffing packets on the network by wrapping libnet and libpcap in a (hopefully) easy-to-use C++ library. This is exactly what we need in order to implement our ad-hoc firewall. More specifically, we need to be able to craft spoofed ARP packets and we also need to be able to sniff incoming packets after poisoning the hosts we want to firewall. In the examples/arp_poisoner directory of the libcyanid source code, I put an example program that demonstrates how libcyanid can be used to inject spoofed ARP packets into the network:

#include <cyanid.hpp>
#include <iostream>

using namespace std;

int main(int argc, char* argv[])
{
    if(argc < 6) {
        cerr << "Usage: arp_poisioner [interface] "
             << "[sha] [spa] [tha] [tpa]" << endl;

    const string iface      = argv[1];
    const string source_mac = argv[2];
    const string source_ip  = argv[3];
    const string target_mac = argv[4];
    const string target_ip  = argv[5];

    cyanid::device device(iface)   

    cyanid::packet packet(device);

    packet.build<cyanid::builder::arp>()(
            cyanid::builder::arp::REPLY,
            source_mac,
            source_ip,
            target_mac,
            target_ip);

    packet.build<cyanid::builder::ethernet>()(
            target_mac,
            cyanid::builder::arp::ETHER_TYPE);

    size_t bytes_written = packet.dispatch();
    cout << "Wrote " << bytes_written
         << " bytes to the network" << endl;

    return 0;
}

The code is pretty self explanatory. We first create a device by specifying the network interface we want to use. We then create a packet to be transmitted over this device, and then we build the necessary packet headers (in reversed order) before the packet is actually dispatched. The next thing we need is a way of capturing packets. A simple packet capturer (very similar to the one found in examples/arp_listener) is shown here:

#include <cyanid.hpp>
#include <iostream>

using namespace std;

class Listener : public cyanid::listener {
public:
    Listener(cyanid::device& device) : listener(device)
    {
        apply_filter("arp");
    }

    void handle_packet(const cyanid::raw_packet& packet)
    {
        size_t packet_size = packet.packet_header()->len;
        cyanid::builder::ethernet eth(
            packet.payload(), packet_size);

        size_t arp_size =
            packet_size - cyanid::builder::ethernet::header_size;
        cyanid::builder::arp arp(eth.payload(), arp_size);

        std::string type = arp.oper() ==
            cyanid::builder::arp::REQUEST ? "REQUEST" : "REPLY";

        cout << "Captured ARP packet: " << endl
            << "============================================"
            << endl << "ARP type: " << type << endl
            << "Source hardware address: " << arp.sha() << endl
            << "Target hardware address: " << arp.tha() << endl
            << "Source protocol address: " << arp.spa() << endl
            << "Target protocol address: " << arp.tpa() << endl
            << endl;
    }
};

int main(int argc, char* argv[])
{
    if(argc < 2) {
        cerr << "Usage: arp_listener [IFACE]" << endl;
        return 1;
    }

    const std::string iface = argv[1];

    cyanid::device device(iface);
    Listener listener(device);
    listener.run();

    return 0;
}

There are a couple of things happening here. First and most importantly, the Listener class. Any listener must override the handle_packet method which is called whenever a packet is captured. A raw packet contains a packet header and the actual data, and is passed as an argument to handle_packet for processing. The next thing we do is to reconstruct the ARP packet we captured from the raw packet. Note that this happens in the opposite order of which the packet was built in the first place. There is one more thing that is important to notice; the call to apply_filter in the constructor. This function (which is inherited from cyanid::listener) enables you to filter the traffic we are capturing in the exact same way as with tcpdump. In this example we tell the listener that we are only interested in capturing ARP packets. Now that we know how to capture and injects packets, we’re ready to get our hands dirty. But first, let’s make a list of what we need our program to do in order to get a working firewall up an running:

  • The ARP cache is updated on a regular basis, so we need to ARP poison our hosts on a regular basis too. Possible strategies:
    • ARP poison our hosts on a fixed time interval. This may be ineffective. For example, if the ARP cache on our hosts for some reason is updated every 20 seconds and we decide to ARP poison our  hosts on a 10 second interval, the host might end up being cut off from our firewall half the time if our timing is bad. This will happen if we ARP poison the target right before the target receives the legit ARP reply.  Likewise, if we’re firewalling many hosts each with an ARP cache being updated approximately every 10 minutes, we might end up flooding the network with unnecessary traffic if we are ARP poisoning our hosts on, let’s say, a 10 or 20 second interval.
    • Listen for ARP requests going to and from our hosts and then ARP poison accordingly. This way we will only send ARP poison when we have to – that is, right after the hosts sends an ARP request. This will also minimize the amount of time our hosts is cut off from the firewall since we’re ARP poisoning our hosts right after the host has sent an ARP request. But there is a chance that this could all backfire if we’re not careful; we must make sure that our reply comes after the legit ARP reply so we need to add some sort of delay to make sure that we send our spoofed ARP reply after the legit ARP reply.
  • When a packet is captured we need to determine the packets destination, and forward it if the packet is allowed through our filter. This might sound like a bit of a hassle, but the only thing we need to do is to duplicate this packet and inject it onto the network. However, we need to replace the spoofed MAC address with the correct one so that the packet is sent to the intended host.
  • We need a filtering mechanism. People spend years of their life perfecting different filtering mechanisms. I’m not one of those people, so I’m gonna go with something real simple, like … no filtering!

Alright, so now we need to come up with a design for our implementation. First off, we need a listener that will capture ARP traffic and keep our target hosts high on our benevolent poison. This must run in a separate thread. Then we need a routing mechanism. This routing mechanism should also be a listener, and should capture all IP-based traffic and forward it to the intended hosts. The routing should be done in a separate thread too. Last but not least, we need a filter. Let us make it simple and create a filter class and pass an instance of it to our routing mechanism.  This way the router can determine whether or not to forward a given packet. After screwing around with this for some (way too much) time, I came up with what seems to be a working (ish) implementation.

25
Sep

Using ARP Poisoning to Create an Ad-Hoc Firewall – Part 1: The Strategy

Some time ago I wrote a small C++ wrapper library around libnet and libpcap to ease the development of various networking applications. After spending some time trying to come up with an idea, I figured I would try and create a very simple ad-hoc firewall by utilizing ARP poisoning (this will be explained shortly) on hosts I wanted to firewall. I know very little about firewalls, so I thought it would be a cool project. Furthermore, it is also a legitimate use of ARP poisoning which is certainly not something you come across every day. In this post I will explain the basic idea behind ARP poisoning and how I intend to use it to create an ad-hoc firewall.

Read moreRead more

Switch to our mobile site