[ISN] Running programs in response to sniffed DNS packets - stealthily managing iptables rules remotely, Part 2

From: InfoSec News (isnat_private)
Date: Fri Aug 15 2003 - 00:59:01 PDT

  • Next message: InfoSec News: "[ISN] FBI outlines security upgrades"

    +------------------------------------------------------------------+
    |  Linux Security: Tips, Tricks, and Hackery                       |
    |  Published by Onsight, Inc.                                      |
    |                                                                  |
    |  14-August-2003                                                  |
    |  http://www.hackinglinuxexposed.com/articles/20030814.html       |
    +------------------------------------------------------------------+
    
    This issue sponsored by Onsight, your Security Solution.
    
    Onsight, Inc is a consulting firm specializing in network security.
    Our network consultants have extensive experience in host security
    for all Unix flavours, from Solaris and *BSD to HP-UX and Irix. We
    can provide custom firewall solutions, Intrusion Detection systems,
    assist in log monitoring and analysis, and clean up your systems
    after successful cracker intrusions.
    
    Of course, our speciality is Linux security and systems - we wrote
    the book on it: Hacking Linux Exposed. If you want to protect your
    Unix network from crackers, you want to talk to us.
    
    For more information, see http://www.onsight.com or email 
    securityat_private
    
    --------------------------------------------------------------------
    
    Running programs in response to sniffed DNS packets - stealthily
    managing iptables rules remotely, Part 2
    By Brian Hatch
    
    Summary: In combination to the watch_dns program which uses Net::Pcap
    to sniff DNS packets, we complete our stealthy remote execution
    setup.
    
    Last time we set up a Perl script that would use the Net::Pcap module
    to sniff the network and print information about DNS requests to
    standard output. The output looks like this
    
       sourceipaddr -> destipaddr: dnshostname
    
    The handle_remote_dns_commands program below will run watch_dns and
    act on the output. This program could be modified to suit any
    purpose. Currently it is set up to manipulate a new iptables chain
    called allow_in which is called before packets are DROPped. Remember,
    this chain must be created with the following command at a point in
    your iptables setup before inbound SYN packets are DROPped.[1]
    
      # iptables --new-chain allow_in
      # iptables -A INPUT -j allow_in
    
    The code below is pretty well commented, so rather than breaking it
    up to discuss the components, just read the comments. After all, code
    is speech.
    
    
    #!/usr/bin/perl
    #
    # handle_remote_dns_commands
    #
    # Copyright 2003, Brian Hatch, released under the GPL.
    #
    #  This program allows you to run commands based on DNS requests that are
    #  sniffed by the 'watch_dns' command described at
    #  http://www.hackinglinuxexposed.com/articles/20030730.html
    #
    #  It reads lines from the watch_dns DNS sniffer which are of the form
    #
    #         sourceipaddr -> destipaddr: dnshostname
    #
    #  The actual commands rules that are run are found by looking up the
    #  dnshostname in the %mapping hash.  The command to be run (the
    #  associated hash value) is an anonymous array.  The array values
    #  are analysed, and if the string SSSSSSSS or DDDDDDDD is present
    #  it is replaced by the source or destination IP address, respectively.
    #
    #  While the current example is for maintaining an iptables chain,
    #  there's no reason you couldn't use it to run any other commands, such
    #  as triggering an outbound SSH connection with remote forward back into
    #  the machine itself, etc.  Use your imagination.
    #
    # BUGS
    #
    #   The script doesn't actually verify an IP address is valid - ie it should
    #   reject "999.888.777.666" because it's outside the valid range.  The
    #   command you call should be able to deal appropriately with invalid IP
    #   addresses.
    #
    #   Since most host/nslookup/dig tools will retry DNS queries if no
    #   response is received, you may end up calling the command multiple
    #   times.  For iptables rules, this isn't terribly important.
    #
    #   Using SIGALRM isn't the most brilliant method to periodically call our
    #   periodic commands.  As written, if a cracker knows valid commands, he
    #   can spew DNS commands that will cause them to be run very quickly.  In
    #   the case of iptables cleaning, this would make it difficult for a
    #   legitimate connection to get in.  However if the SIGALRM were written
    #   to always cause an X second timer without the fancy footwork, then
    #   said cracker could cause our chain to grow infinitely long, eventually
    #   maxing it out and causing a DoS, because the chain would never be
    #   cleared.  The code used is probably best, since it will fail closed.
    #
    #   There is obviously no authentication or encryption whatsoever.  If
    #   someone gleans your magical commands, they can cause the associated
    #   commands to be run.
    
    use strict ;
    
    # If $PERIODIC_SECONDS nonzero, then every (this many) seconds we should
    # run the commands stored in the @periodic_commands array.
    my $PERIODIC_SECONDS = 10;
    
    # Location of watch_dns command (will be run as our UID which must be
    # root since it's sniffing.  If you are running this script as a normal
    # user, you'll want to run watch_dns via sudo.)
    my $WATCH_DNS="/opt/bin/watch_dns";
    
    # Should debug and warning messages be written to STDOUT?
    my $DEBUG=0;
    my $WARNING=0;
    
    
    
    ####
    # Modify this section to include your actual functionality.
    
      # Local variables we may need
      my $IPTABLES="/sbin/iptables";
      
      # Which chain should we enter the temporary access rules?
      my $CHAIN="allow_in";
      
      my @periodic_commands = (
              [ $IPTABLES, '-F', $CHAIN ],
      );
      
      # The actual rules to run when incoming DNS hostnames match.
      #
      my %mapping = (
        openssh =>
            [ $IPTABLES, '-A', $CHAIN,
              qw( -p tcp --source SSSSSSSS/32 --dport 22 -j ACCEPT ) ],
    
        # Other examples.
        #
        #opensmtp =>
        #   [ $IPTABLES, '-A', $CHAIN,
        #     qw( -p tcp --source SSSSSSSS/32 --dport 25 -j ACCEPT ) ],
        #
        #allow-all =>
        #   [ $IPTABLES, '-A', $CHAIN, qw( -p tcp -j ACCEPT ) ],
        #
        #flush.subdomain.example.com =>
        #   [ $IPTABLES, '-A", $CHAIN, '-F' ],
        
      );
    
    # End of purpose-specific modifications.
    ####
    
    
    # No more changes needed hereafter.
    
    if ( $PERIODIC_SECONDS ) {
            # Set up an alarm signal handler. When an alarm is received,
            # flush the iptables exceptions table, denying everyone again.
            $SIG{ALRM} = \&run_periodic_commands;
    }
    
    # Start our pcap sniffer, and snag it's output.
    open WATCH_DNS, "$WATCH_DNS |" or die "Can't start watch_dns";
    
    # Loop indefinitely
    while (<WATCH_DNS>) {
        my $iptables_cmd;
        my @iptables_cmd;
    
        # Let's be very paranoid about checking our input.
        # Both the source and destination IP addresses we
        # get could be forged by an attacker.  Let's at least
        # make sure that they're in the correct form.
        my ($src, $dst, $command) =
             /^ (\d+ \. \d+ \. \d+ \. \d+)  # first IP address
                \s* -> \s*                  # arrow
                (\d+ \. \d+ \. \d+ \. \d+)  # second IP address
                : \s* (\S+)                 # command (hostname)
            /x;
    
        unless ( $command ) {               # ignore bad input.
                print "ignoring $_" if $DEBUG;
                next;
        }
    
        if ( @iptables_cmd = @{$mapping{$command}} ) {
    
            map { s/DDDDDDDD/$dst/g } @iptables_cmd;
            map { s/SSSSSSSS/$src/g } @iptables_cmd;
    
            print "Running @iptables_cmd\n" if $DEBUG;
    
            # System used with a list doesn't invoke a shell.
            system @iptables_cmd;
            
            if ( $PERIODIC_SECONDS ) {
                    # Set the alarm 
                    my $oldtimer = alarm($PERIODIC_SECONDS);
                    if ( $oldtimer == 1 ) {
                            &{$SIG{ALRM}};          # Call immediately
                    } elsif ( $oldtimer ) {
                            alarm(--$oldtimer);     # Decrement alarm
                    }
            }
    
        } else {
            print "ignoring $command\n" if $WARNING;
        }
    }
    
    
    sub run_periodic_commands {
            print "run_periodic_commands called.\n" if $DEBUG;
    
            # System used with a list doesn't invoke a shell.
            for my $command_arrayref ( @periodic_commands ) {
                    system @$command_arrayref;
            }
    }
    
    
    
    Ok, next week I'll show you how to send the DNS query to the sniffer
    so we can wrap this whole thing up. The end is near...
    
    NOTES:
    
    [1] In the script we created two weeks ago, it could go any place
    before the DROP rule is called.
    
                                -------------                            
    Brian Hatch is Chief Hacker at Onsight, Inc and author of Hacking
    Linux Exposed and Building Linux VPNs. He loves to create
    functionality from horrible bastardizations of existing protocols.
    Brian can be reached at brianat_private
    
    --------------------------------------------------------------------
    This newsletter is distributed by Onsight, Inc.
    
    The list is managed with MailMan (http://www.list.org). You can
    subscribe, unsubscribe, or change your password by visiting
    http://lists.onsight.com/ or by sending email to
    linux_security-requestat_private
    
    Archives of this and previous newsletters are available at
    http://www.hackinglinuxexposed.com/articles/
    
    --------------------------------------------------------------------
    
    Copyright 2003, Brian Hatch.
    
    
    
    -
    ISN is currently hosted by Attrition.org
    
    To unsubscribe email majordomoat_private with 'unsubscribe isn'
    in the BODY of the mail.
    



    This archive was generated by hypermail 2b30 : Fri Aug 15 2003 - 04:35:45 PDT