Team LiB
Previous Section Next Section

2.3. Writing an Ettercap Plug-in

You can enable or disable Ettercap plug-ins on the fly, and therefore you can use them to extend Ettercap functionality on demand. Ettercap comes bundled with a variety of plug-ins that you can find in the plug-ins directory of the Ettercap source tree. The following sections show you how to write find_tcp_conn, a plug-in that detects the initiation of a new TCP connection on the network.

2.3.1. The find_tcp_conn Plug-in

To establish a TCP connection with a remote host, the source host sends a TCP packet with the SYN flag set to the remote host. If the remote host is listening on a particular port, it responds with a TCP packet with the SYN and ACK flags set. The source host then sends a TCP packet with the ACK bit set to formally establish the TCP connection. This sequence is known as the three-way TCP handshake . Therefore, to detect new TCP connections with other hosts, our plug-in has to analyze the network traffic for TCP packets that have the SYN flag set. The find_tcp_conn plug-in described in the following paragraphs analyzes TCP packets for the SYN flag, and if one is found, it alerts the Ettercap user that a host on the network is attempting to establish a new TCP connection with another host.

The find_tcp_conn plug-in alerts the Ettercap user whenever a TCP packet with the SYN flag set is captured. Therefore, the plug-in alerts the Ettercap user even if the server host does not respond to the connection attempt. This plug-in can be useful for noticing when a SYN port-scan is being performed on a network.

The find_tcp_conn plug-in will not detect new TCP connections when the host running Ettercap is on a network switch because network switches attempt to segregate network traffic. Therefore, the find_tcp_conn plug-in will detect SYN packets from other hosts only when the host running Ettercap is on a network hub, or when Ettercap is instructed to perform ARP poisoning.


Every Ettercap plug-in needs to include ec.h and ec_plugins.h. These files contain required global variables and plug-in APIs. The plug-in uses the packet_object structure defined in ec_packet.h along with various functions defined in ec_hook.h, so these header files need to be included as well:

#include <ec.h>
#include <ec_plugins.h>
#include <ec_packet.h>
#include <ec_hook.h>

All Ettercap plug-ins should declare plugin_load(), which serves as the entry point of a plug-in. Following is its prototype:

int plugin_load(void *);

Following is the prototype of find_tcp_conn_init( ), which is called when the plug-in is enabled, and find_tcp_conn_fini( ), which is called when the plug-in is disabled:

static int find_tcp_conn_init(void *);
static int find_tcp_conn_fini(void *);

The plug-in invokes parse_tcp() when a TCP packet is received. Here is its prototype:

static void parse_tcp(struct packet_object *po);

The plugin_register( ) function in plugin_load() accepts a structure of type plugin_ops . Following is the definition of find_tcp_conn_ops, which is an instance of plugin_ops:

struct plugin_ops find_tcp_conn_ops = {
   /* ettercap version MUST be the global EC_VERSION */
   ettercap_version: EC_VERSION,
   /* the name of the plugin */
   name:             "find_tcp_conn",
    /* a short description of the plugin (max 50 chars) */
   info:             "Detect TCP connections",
   /* the plugin version. */
   version:          "1.0",
   /* activation function */
   init:             &find_tcp_conn_init,
   /* deactivation function */
   fini:             &find_tcp_conn_fini,
};

Most of the items defined by find_tcp_conn_ops are self-explanatory. Note that ettercap_version must be set to EC_VERSION. Ettercap uses this value to prevent a plug-in compiled for a different version of Ettercap from attempting to load. The init item declares the function that is called when the user enables the plug-in, and the fini item declares the function that is called when the user disables the plug-in. For example, in the Ettercap GTK frontend, you can enable or disable plug-ins by selecting "Manage the plugins" from the Plugins menu and double-clicking the plug-in names.

Following is the definition of plugin_load( ), which is called when the plug-in is loaded. Users can load a plug-in by pressing Ctrl-O from the GTK frontend and selecting the appropriate plug-in file.

int plugin_load(void *handle)
{
    return plugin_register(handle, &find_tcp_conn_ops);
}

Every plug-in must be assigned a unique handle, which the Ettercap engine generates when it invokes plugin_load( ). As a plug-in author, you simply need to pass handle to plugin_register( ) as its first parameter. The second parameter, find_tcp_conn_ops, is the structure we declared in the previous paragraphs. As we already have seen, this structure defines plug-in details as well as the init and fini items.

Following is the definition of find_tcp_conn_init( ), which is defined as our init function and is called when the Ettercap user enables the plug-in:

static int find_tcp_conn_init(void *dummy)
{
    USER_MSG("find_tcp_conn: plugin running...\n");

    hook_add(HOOK_PACKET_TCP, &parse_tcp);

    return PLUGIN_RUNNING;
}

The USER_MSG( ) macro displays the given string to the Ettercap user. In the case of the GTK frontend, the string is displayed in the lower section of the GUI. In this case, the plug-in displays the string find_tcp_conn: plugin running... to let the user know the plug-in has been enabled. The hook_add() function takes in two parameters. Following is its prototype:

void hook_add(int point, void (*func)(struct packet_object *po))

You use the point parameter to decide when the plug-in hook function is to be called. We pass HOOK_PACKET_TCP as the point parameter to hook_add( ) to indicate that we want parse_tcp( ) to be called every time Ettercap captures a TCP packet on the network. (For an explanation of other types of hooking points, see the doc/plugins text file in the Ettercap source tree.) The find_tcp_conn_init( ) function returns PLUGIN_RUNNING, which indicates to the Ettercap engine that the plug-in has initialized successfully.

Here is a definition of find_tcp_conn_fini( ), which is invoked when the Ettercap user disables the plug-in:

static int find_tcp_conn_fini(void *dummy)
{
    USER_MSG("find_tcp_conn: plugin terminated...\n");

    hook_del(HOOK_PACKET_TCP, &parse_tcp); 

    return PLUGIN_FINISHED;
}

The hook_del( ) function removes the parse_tcp( ) function as the hook function. After hook_del( ) returns, the Ettercap engine no longer invokes parse_tcp( ) when a TCP packet is received. The find_tcp_conn_fini( ) function returns PLUGIN_FINISHED to indicate to the Ettercap engine that the plug-in finished and can be deallocated.

Following is the definition of the parse_tcp( ) function, which is called whenever Ettercap receives a TCP packet:

static void parse_tcp(struct packet_object *po)
{
   char tmp1[MAX_ASCII_ADDR_LEN];
   char tmp2[MAX_ASCII_ADDR_LEN];

   if ( po->L4.flags != TH_SYN )
      return;
   
   USER_MSG("find_tcp_conn: Probable connection attempt %s -> %s [%d]\n",
ip_addr_ntoa(&po->L3.src, tmp1), ip_addr_ntoa(&po->L3.dst, tmp2), ntohs(po->L4.dst));
}

The if block inspects po, which contains the TCP packet captured by Ettercap. If the packet does not have the SYN flag set, L4.flags will not be equal to TH_SYN, and the function simply returns. The L4 structure signifies " Layer 4," also known as the Transport Layer of the OSI model where TCP operates. L3 signifies " Layer 3," also known as the Network Layer" where the IP operates.

USER_MSG is invoked only if the previous if block did not return, in which case we can be certain that the captured TCP packet has the SYN flag set. Therefore, we call USER_MSG() to alert the user that an attempt to establish a new TCP connection was detected, as shown in Figure 2-2. The ip_addr_ntoa() function accepts an IP address of type ip_addr as the first parameter and returns a string representation when given a char pointer as its second parameter. Because po->L3.src and po->L3.dst contain the source and destination IP addresses of the packet and are of type ip_addr, the plug-in invokes ip_addr_ntoa( ) to convert them to strings to display them to the user via USER_MSG( ). The ntohs( ) function is passed po->L4.dst as the parameter, which contains the destination port. The ntohs( ) function converts a given value from network byte order to host byte order. This is useful in preserving portability because different CPUs use different byte orders.

Figure 2-2. The find_tcp_conn plug-in in action


2.3.2. find_tcp_conn.c

The easiest way to compile this plug-in is to make a new directory called find_tcp_conn in the plug-ins directory in the Ettercap source tree. Then, copy over the Makefile from another plug-in called find_conn, and replace all occurrences of find_conn with find_tcp_conn. Run make, and you will end up with ec_find_tcp_conn.so in the .libs/ directory. To load this plug-in from the GTK frontend, press Ctrl-O and select this file. Press Ctrl-P to go to the plug-in management section, and double-click the "find_tcp_conn" entry to enable the plug-in. Here is the complete source code for find_tcp_conn.c for easy reference:

#include <ec.h>                        /* required for global variables */
#include <ec_plugins.h>                /* required for plugin ops */
#include <ec_packet.h>
#include <ec_hook.h>

/* prototypes */
int plugin_load(void *);
static int find_tcp_conn_init(void *);
static int find_tcp_conn_fini(void *);
static void parse_tcp(struct packet_object *po);

/* plugin operations */
struct plugin_ops find_tcp_conn_ops = {
    /* ettercap version MUST be the global EC_VERSION */
    ettercap_version: EC_VERSION,
    /* the name of the plugin */
    name:             "find_tcp_conn",
    /* a short description of the plugin (max 50 chars) */
    info:             "Detect TCP connections",
    /* the plugin version. */
    version:          "1.0",
    /* activation function */
    init:             &find_tcp_conn_init,
    /* deactivation function */
    fini:             &find_tcp_conn_fini,
};
/* this function is called on plugin load */
int plugin_load(void *handle)
{  
    return plugin_register(handle, &find_tcp_conn_ops);
}

static int find_tcp_conn_init(void *dummy)
{
    USER_MSG("find_tcp_conn: plugin running...\n");

    hook_add(HOOK_PACKET_TCP, &parse_tcp);

    return PLUGIN_RUNNING;
}

static int find_tcp_conn_fini(void *dummy)
{
    USER_MSG("find_tcp_conn: plugin terminated...\n");
  
    hook_del(HOOK_PACKET_TCP, &parse_tcp);

    return PLUGIN_FINISHED;
}

/* Parse the TCP request */
static void parse_tcp(struct packet_object *po)
{
    char tmp1[MAX_ASCII_ADDR_LEN];
    char tmp2[MAX_ASCII_ADDR_LEN];
   
    if ( po->L4.flags != TH_SYN )
        return;

    USER_MSG("find_tcp_conn: Probable connection attempt %s -> %s [%d]\n",
ip_addr_ntoa(&po->L3.src, tmp1), ip_addr_ntoa(&po->L3.dst, tmp2),
ntohs(po->L4.dst));
}

See the doc/plugins text file within the Ettercap source tree for a listing and description of other useful plug-in-related function calls.


    Team LiB
    Previous Section Next Section