The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

HoneyClient::Manager::FW - Perl module to remotely handle firewall rule/chain creation and deletion which will provide network connectivity for the honeyclients during crawling. Additionally, it will provide protection when the honeyclients become compromised by enabling static rate limiting(tcp/udp/icmp) and MAC address filtering.

VERSION

This documentation refers to HoneyClient::Manager::FW version 0.99.

SYNOPSIS

CREATING THE SOAP SERVER

  # Make sure HoneyClient::Util::Config loads properly
use HoneyClient::Util::Config qw(getVar);

# Make sure IPTables::IPv4 loads use IPTables::IPv4;

# Make sure HoneyClient::Manager::FW can load use HoneyClient::Manager::Firewall::FW;

# Make sure HoneyClient::Util::SOAP loads properly require_ok('HoneyClient::Util::SOAP');

package HoneyClient::Manager::Firewall::FW; use HoneyClient::Util::SOAP qw(getClientHandle getServerHandle); my $daemon = getServerHandle(); $daemon->handle;

The SOAP firewall server will boot up when the honeywall is started by the HoneyClient manager. The main directory that holds all the listener code is the /hc directory. startFWListener.pl is located in the /etc/rc.d/rc3.d directory and will boot up when the honeywall starts up in run level three. After start up, the firewall listener will await calls from the HoneyClient manager so that the firewall may be configured properly and dynamically updated when crawling begins.

Steps to get honeyclient listening:

1. Boot up honeyclient honeywall vmware image. 2. Start up our SOAP firewall and SOAP log listener /usr/bin/perl /hc/startFWListener.pl > /dev/null 2> /dev/null & These will start upon boot of the honeywall so you will not have to do anything except boot the image. 3. Now the firewall is listening for all SOAP client calls 4. Do a "ps -xf" to confirm that your firewall is listening It should show something like: 7580 pts/0 S 0:01 /usr/bin/perl /hc/startFWListener.pl 5. Make your FW calls now from honeyclient-client.pl.

INTERACTING WITH SOAP SERVER

 use HoneyClient::Util::SOAP qw(getClientHandle);
 use HoneyClient::Util::Config qw(getVar);

After the honeywall boots up, startFWListerner.pl will be executed and begin listening. From here we want to start interacting with our SOAP FW server.

 # Create a new SOAP client, to talk to the HoneyClient::Manager::FW module
 # @initlist will contain all the return values sent back from the server (PID of startFWListerner.pl on server and status message)
 #  Lets set our default honeyclient ruleset:
  my $stub = getClientHandle(namespace => "HoneyClient::Manager::FW");
  my $som = $stub->fwInit();
  my @initlist = $som->paramsall;
  print "$_\n" foreach (@initlist);

 # To dynamically append new rules to the iptables ruleset, do the following
$hashref = this data structure will be passed from the manager to the HoneyClient::Manager::FW

 $som = $stub->addRule( $hashref );
 print $stub->result;
 print "\n";

# To dynamically delete rules, all you need to do is delete the user-defined chain that was originally created.

$som = $stub->deleteChain( $hashref ); print $stub->result; print "\n";

# To get the status of the current iptables ruleset, this function prints to hard disk the working iptables ruleset $som = $stub->getStatus(); print $stub->result; print "\n";

# For all new VM's that we plan to add later on, we will have to add new VM chains: $som = $stub->addChain( $hashref); print $stub->result; print "\n";

 # To shutdown the Firewall SOAP listner on the Honeywall
$som = $stub->FWShutdown();
print $stub->result;
print "\n";

DESCRIPTION

Once created, the daemon acts as a stand-alone SOAP server, processing individual requests from the HoneyClient manager and manipulating the IPTables ruleset on the transparent virtual honeywall.

# This package name. our $PACKAGE = __PACKAGE__; our $DAEMON_PID : shared = undef; # Complete URL of SOAP server, when initialized. our $URL_BASE; our $URL; our $UPTIME = "/usr/bin/uptime";

BEGIN {

        # Defines which functions can be called externally.
        require Exporter;
        our ( @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS, $VERSION );

        # Set our package version.
        $VERSION = 0.99;

        @ISA = qw(Exporter);

        # Symbols to export automatically
        @EXPORT =
          qw( _parseHash _validateInit init_fw destroy_fw _doFullBackup _flushChains _setAcceptPolicy _setDefaultDeny _set_log_rules _setstaticrate _setDefaultRules _remoteConnection _set_ip_forwarding _getpid);

        # Items to export into callers namespace by default. Note: do not export
        # names by default without a very good reason. Use EXPORT_OK instead.
        # Do not simply export all your public functions/methods/constants.

        # This allows declaration use HoneyClient::Manager::FW ':all';
        # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
        # will save memory.

        %EXPORT_TAGS = ( 'all' => [qw(init_fw destroy_fw)], );

        # Symbols to autoexport (when qw(:all) tag is used)
        @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );

        $SIG{PIPE} = 'IGNORE';    # Do not exit on broken pipes.
}

EXTERNAL SOAP FUNCTIONS

  • fwInit()

    The fwInit function awaits a call from the Honeyclient manager, once a call is made the function performs numerous subfunctions but mainly handles creation of the default iptables ruleset for the honeyclient network. IPTables ruleset: Since we are using our honeywall to do transparent packet forwarding, forwarded packets will be traversing the IPTables FORWARD chain, which is associated with the filter table. By adding rules to the FORWARD chain, you can control the flow of traffic between our two networks (honeyclient and external network). Instead of using a single, built-in chain for all protocols, we use a user-defined chain to determine the protocol type, then hand off the actual final processing to our user-defined chain in the filter table.

    Inputs: nothing - No specific input Output: Success if default ruleset was created, failure if not

    #=back

  • _validateInit() is another helper function

    Inputs: no input Output: total number of rules across all chains (Default and user-defined)

  • _parseHash() is another helper function that takes in a hash reference from the honeyclient manager and parses the data structure thus producing usable values to generate our firewall rules.

    Inputs: Requires hash reference (hohohohoh). Output: returns hash of a hash to be used during the addRule() function for rule generation.

  • addChain();

    add_vm_chain adds the user-defined chain based on manager client parameters.

    Inputs: $classis the package name $hashref - hash reference that will be sent over from HoneyClient::Agent. It will then be parsed by get_vm_from_hash() and give me an array of VM names that will be added from the iptables chain list. The reason we have broken add_vm_chain() up and made it its separate subroutine is because when we add a rule to the iptables ruleset, we must first have a user-defined chain in place. A commit must occur which writes it to the kernel-level netfilter subsystem, then the rule must be added after that has occurred.

    Output: returns true if VM chain was deleted, returns false if not

    #=back

  • deleteChain();

    delete_vm_chain deletes the user-defined chain based on manager client parameters.

    Inputs: $classis the package name $hashref - hash reference that will be sent over from HoneyClient::Agent. It will then be parsed by get_vm_from_hash() and give me an array of VM names that will be deleted from the iptables chain list.

    Output: returns true if VM chain was deleted, returns false if not

  • addRule($hashref)

    addRule is a function that handles the addition of a new iptable rule into the existing IPTables ruleset which allow honeyclients functionality to crawl the internet in search of malicious web sites. FWPunch first checks for the existance of the user-defined chain before it creates a new VM rule. If the chain already exists, the rule can not be added since their is no corresponding chain. If it does exist, the rule is added successfully. All FWPunch calls are logged.

    The addRule() function will recieve a $hashref which will be a muli-level hash table whose structure will resemble the below data structure:

    my $hashref = {

        '0d599f0ec05c3bda8c3b8a6' => {    # VM identifier.
            # You'll notice that we add a new layer to the table.
            # This is an MD5SUM that represents the unique identifier
            # of the VM *NAME*.  You can assume that this name will be
            # initially generated and used by HC::Manager::VM.
    
            # The next 2 keys contain the data from HC::Agent::Driver->next()
            'targets' => {    # This keyname used to be called 'servers'
    
                # The browser will contact 'www.mitre.org' at
                # TCP port 80.
                'www.mitre.org'   => { 'tcp' => [ 80 ], },
                'rcf.mitre.org'   => { 'tcp' => [ 80 ], },
                'blogs.mitre.org' => { 'tcp' => [ 80 ], },
                'www.cnn.com'     => { 'tcp' => [ 80, 8080 ], },
                'pool.ntp.org'    => { 'udp' => [ 123, ], },
    
                # General example:
                # The application will contact '192.168.1.1' at
                # some unknown TCP port.
                #
                # If the ports are unknown, the firewall
                # should allow outbound contact to all unprivileged
                # ports (1025-65535) on the specified server. (Yes, I
                # realize in reality, there's an upstream DMZ firewall
                # blocking this functionality; this is simply an
                # architectural design, for now.)
                #'192.168.1.1' => { 'tcp' => "undef", },
    
                # Or, more generically:
                #'hostname_or_IP' => {
                #    'protocol_type' => [ portnumbers_as_list ],
                #},
    
            },
    
            'resources' => {
    
                # This hashtable contains a list of key, value pairs
                # that reflect the list of resources that the driver
                # will contact next. For browsers, this means URLs.
                # The (1) value is simply a numerical
                # placeholder that serves no purpose, for now.
                'http://www.mitre.org' => 1,
            },
    
            # Now, we expect HC::Manager to add this next key.
            # This sub-hashtable contains all the source IPs, ports,
            # and protocols that the VM will use to make its outbound
            # connection to remote resources.
            'sources' => {
    
                '00:04:23:08:7d:54' => { # The VM's MAC address.
    
                    '10.0.0.128' => {    # The VM's internal IP.
    
                        # In most cases, a VM will only _have_ one
                        # NAT-ted IP.  However, this format allows for the
                        # remote possibility that a VM may have multiple
                        # virtual NICs or multiple IP aliases, in which case
                        # the VM may have multiple source IPs.
    
                        'tcp' => undef,
    
                        # We use the same protocol => port syntax as described
                        # before.  Again, if the value is 'undef', then that
                        # indicates that the VM may use any unprivileged port
                        # locally inside its OS, when initiating outbound
                        # communication to the remote resource.
    
                        'udp' => [ 23, 53, '80:1024', ],
                    },
                },
            },
        },
    };

    Inputs: $class is the package name. $hashref

    Output: Return true if success or false if failure

  • _getVMName($hashref);

    This function extracts the VM name from the hash reference and will use it in the addChain() function later.

    Inputs: $hashrefis the hash reference sent from the HoneyClient::Agent->HoneyClient::Manager->HoneyClient::Manager::FW

    Output: Returns the VM name.

  • init_fw()

    The following init_fw() and destroy_fw() functions are the only direct calls required to startup and shutdown the SOAP server.

    Input: $class, $localAddr, $localPort

    Output: n/a

  • destroy_fw()

    Terminates the SOAP server within the child process.

  • _load_interfaces()

    Loads the interfaces listed in the /etc/interfaces.conf file (function not active yet)

    Input: filename

    Output: n/a

  • _flushChains()

    Gets the current list of chains within the IPTables ruleset and flushes all corresponding rules, then deletes the actual chain.

    Input: No input

    Output: Return true if success for the flushing and deleting, returns false if unsuccessful

  • _setAcceptPolicy()

    Grabs the current list of chains within the IPTables ruleset and sets the policy to ACCEPT.

    Input: No input

    Output: Return true if the commit was successful, returns false if unsuccessful. $table->commit() attempts to commit all changes made to the IP chains in the table that $table points to, and closes the connection to the kernel-level netfilter subsystem. If you wish to apply your changes back to the kernel, you must call this.

  • _setDefaultDeny()

    Gets the current list of chains and sets the firewall policy to DROP.

    Input: No input

    Output: Return true if successful commit, returns false if unsuccessful commit

  • _setDefaultRules()

    This function parses the /etc/resolv.conf file and grabs the DNS settings, then creates iptables rules on the INPUT/FORWARD and OUTPUT chains from thoses DNS settings. Additionally, we create rules to allow the firewall to talk to itself via the localhost.

    Additionally, at the end of the opendefault function are two rules:

    "iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT" "iptables -A FORWARD -i eth1 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT"

    These rules track state and allow traffic to be forwarded in both directions. It also only allows initiated 10.0.0.0/24 outbound traffic to be sent. This is necessary since we only want our honeyclients to recieve traffic that they initiated and no other. For starters, our honeyclients will just be examining HTTP traffic but might be examining other protocols in the future. Either way, all established and initiated connections that match this rule and be allowed out.

    Input: No input

    Output: Return true if successful commit, returns false if unsuccessful commit

  • _createNat()

    Create a NAT rule that allows for all HoneyClient VM's to have access through the Honeywall. We are using a Masquerading rule, masquerading is a simplified form of SNAT (source NAT) in which packets receive the IP address of the output interface as their source address.

    Input: No input

    Output: Output is a bolean value for succes or failure during the rule insertion.

  • _createPreroutingLogging()

    Create a logging rule for the NAT table (PREROUTING chain) in which we log all traffic that does match the specified rule.

    Input: No input

    Output: Output is a boolean value for succes or failure during the rule insertion.

  • _getdns()

    This function grabs the DNS settings from the /etc/resolv.conf file. It assumes that the default location for these settings will be in that file. However, it does check and make sure that it is a linux box first.

    Input: No input

    Output: Returns a complete list of nameservers if true, if not true, returns value of linux variable which should be 0

  • _createDropLog()

    Create a user-defined chain called Drop_Log which logs and drops all rules that do not match rules within the INPUT and OUTPUT chains.

    Input: No input

    Output: Return true if successful , returns false if unsuccessful append.

  • _doFullBackup()

    Does a complete backup to hard disk of the current active iptables ruleset.

    Input: Requires the $outputdir where the file will be written to.

    Output: Returns void; dies if failure.

  • _setstaticrate()

    This function creates a static rate limiting rule for our default honeyclient default ruleset. For testing purposes, I allow an initial burst of 10 tcp/udp/icmp packets, then gives you 5 packets per minute thereafter.

    Input: Requires the $outputdir where the file will be written to.

    Output: Return true if commit success or false if commit failure

  • _remoteConnection()

    This function opens a few remote connection holes within our honeyclient firewall, more specifically ssh and 8082/tcp (used for connection to/from GSX server manager module)

    Input: No input

    Output: Return true if successful commit, returns false if unsuccessful commit

  • _set_ip_forwarding()

    Set the /proc/sys/net/ipv4/ip_forward file to a value supplied by the user

    Input: $value which will be either 0 or 1

    Output: nothing

  • _checkRoot()

    Checks to make sure FW.pm is running as root user (uid 0).

    Input: No input

    Output: Return true if success or false if failure

  • [NOT IMPLEMENTED AT THIS TIME]: _rule_exists() function checks for the existance of rules within our IPTables ruleset. Within this function, we are checking the rules within the user-defined chains that we have created. If there is a match within the "input" VM, we consider that a match since when the rule is initially appended, it is appended to both the VM#-in and VM#-out chains. Here, I am only testing against the VM#-in chain since if the rule is in one, it has to be in both.

    Inputs: $tableis the object type of IPTables::IPv4::Table. $vin is the VM input chain name. $vout is the VM output chain name. %rule is a hash containing source, destination, and protocol values.

    Output: Return true if success or false if failure

  • [NOT IMPLEMENTED AT THIS TIME]: _translate($url);

    The translate function converts a host name to dotted quad format.

    Inputs: $urlis the domain name that will be converted to dotted quad format.

    Output: Return the domain name as an IP address.

  • getStatus();

    Gets the current iptables ruleset for all the chains (both default and user-defined) and writes them to hard disk. Loop through each chain which gets you the list of chain names. The function list_rules() returns an array of hash references, which contain descriptions of each rule in the chain chainname. Below is the core of the function FWStatus().

            foreach $chainname(@chainlist){
                    print "\n$chainname\n";
                    my @chainrules = $table->list_rules($chainname);
                    for my $href (@chainrules){
                            for $line (keys %$href){
                                    print FWSTATUS "$line=$href->{$line} ";
                            }
                    print "\n";
                    }
            }

    Inputs: $classis the name of the package.

    Output: nothing

  • _iplookup();

    _iplookup takes a domain name ($dest) and performs a DNS query to find an IP address or IP addresses corresponding to that domain name. Currently, _resolveHost() is being used.

    Inputs: $dest is a domain name that will be queried to retrieve corresponding IP addresses.

    Output: An array of resolved IP addresses. If the array only contains one value, then just the one value is in the array.

  • [NOT IMPLEMENTED AT THIS TIME]: insertMac();

    insertMac function add mac address filtering (Anti-spoofing) rules after the VM user-chains are created. They must be remotely called after the vm_add_chain() function.

    Inputs: $chain is the name of the chain that you will be applying the Mac filtering to. $ip is the VM ip address that will be filtered. $mac is the mac address of the VM honeyclient.

    Output: returns nothing

  • _chain_exists();

    _chain_exists tests to see if the chain already exists within the IPTables ruleset.

    Inputs: $vmindex is the Virtual Machine index number that will be used for comparing to the array of existing chains.

    Output: returns true if chain exists, fales if it does not exist.

  • [NOT IMPLEMENTED AT THIS TIME]: isAlive();

    Tests for existance of a file to verify if firewall has been started (not currently active)

    Inputs: $pidfile is the name of the created PID file.

    Output: creation of file with resolved IP addresses.

  • _getLogtime();

    gets the time based on the OS time

    Inputs: nothing

    Output: current time

  • FWShutdown();

    This function first flushes and deletes all the chains in the IPTables ruleset, then sets the ACCEPT policy to all the default chains (INPUT, FORWARD, and OUTPUT). Additionally, the function then loops through the process table and kills all processes with "startFWListener.sh" in the process commandline (of which there should only be one).

    Inputs: nothing Output: process will be killed

  • starttestProcess() - system command to start the SOAP FW listener. This function is used strictly for pod2test purposes.

    Inputs: nothing Output: nothing

  • findProcess() - used for test purposes only to find a started SOAP server listener.

    Inputs: class name Output: returns the boolean value, true or false

  • _getpid();

    _getpid() takes in 1 argument and returns the $pid of the SOAP firewall listener.

    Inputs: Takes in the process name (name of the listener) Output: returns the process ID number

  • [NOT IMPLEMENTED AT THIS TIME]: _sendMail() is a helper function that sends email to other systems informing them of various actions with the firewall.

    _sendMail will send mail to the root account at localhost informing the root user of various firewall actions Inputs: $from is where the user is sending from $to is where the user is sending to $subject is the subject of the email $body is content of the email Output: returns nothing for now

  • [NOT IMPLEMENTED AT THIS TIME]: getcpuload is a function that gives you the cpuload of the OS firewall. This should help give a better understanding of how the firewall OS is running.

    Inputs: nothing Output: cpu load of the OS FW

  • _getip gets the current IP address and mask of the specified interface.

    Inputs: Requires the interface so that it can find the IP address of that interface Output: IP address and Mask of that interface

  • _getmac gets the current MAC address of the specified interface.

    Inputs: Requires the interface so that it can find the MAC address of that interface Output: returns the mac address of the interface

  • _resolveHost() is a helper function that takes in destination domain name and spits out an array list of resolved ip addresses

    Inputs: Requires domain name ($host) Output: returns array list of resolved IP addresses

  • fwOff() opens up our firewall.

    Inputs: n/a Output: nothing

  • killProcess();

    This is a function kills all systems process based on the command line name give via the remote call. It looks through the process table and removes all processes with that key name.

    <Inputs>: no input

    Output: destruction of all Process IDs.

  • [NOT IMPLEMENTED AT THIS TIME]: checkDiskSize();

    checkDiskSize() checks the size of the honeywall partitions and makes sure the disk does not fill up. If it reaches a certain level (90%), then it shoots off an email to root and logs it to hard disk.

    Inputs: no inputs

    Output: outputs the percentage of hard disk that is filled per partition.

  • [NOT IMPLEMENTED AT THIS TIME]: isCompromised();

    isCompromised() checks the iptables log files to see if there has been a compromise to one of the VM images.

    Inputs: hash reference($hashref)

    Output: none

  • checkLog();

    checkLog() checks for network anomalies (MAC address spoofing) or any blocked outbound traffic that orginates from anywhere from the VM subnet.

    Inputs: hash reference($hashref)

    Output: none

  • runTcpdump() - starts a tcpdump procces for a specified VM machine.

    Inputs: VM name and the source IP address of the image.

    Output: none

  • clearTcpdump() - Deletes the corresponding tcpdump .pcap file, then creates a new file for logging.

    Inputs: none

    Output: none

  • removeTcpdump() - removes the corresponding tcpdump .pcap file

    Inputs: VM name and the source IP address of the image.

    Output: none

  • _getSourceIP() - gets the source IP address from the hash table sent from the HoneyClient Manager

    Inputs: hash reference Output: source ip address

  • testConnect() - will allow the user to test connectivity for all their VM's sitting on the backend network behind the honeywall.

    Inputs: package name is passed by default

    Output: $success; boolean value to determine if iptables inserted the rules or not.

SEE ALSO

http://www.honeyclient.org/trac

SOAP::Lite, SOAP::Transport::HTTP

http://www.soaplite.com

IPTables::IPv4

Net::DNS

IPTables Perl API http://sourceforge.net/projects/iptperl/

Data::Dumper, English, Proc::ProcessTable, FileHandle

http://www.honeyclient.org/trac

REPORTING BUGS

http://www.honeyclient.org/trac/newticket

ACKNOWLEDGEMENTS

Derrik Pates for providing the IPTables perl API code and to the sourceforge perl API mailing list for providing detailed support about the IPTables::IPv4 module.

AUTHOR

JD Durick, <jdurick@mitre.org>

Xeno Kovah, <xkovah@mitre.org>

COPYRIGHT AND LICENSE

Copyright (C) 2007 The MITRE Corporation. All rights reserved.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.6 or, at your option, any later version of Perl 5 you may have available.

2 POD Errors

The following errors were encountered while parsing the POD:

Around line 1151:

'=item' outside of any '=over'

Around line 3322:

You forgot a '=back' before '=head1'