Quantcast

Running Programs in Response to Sniffed DNS Packets – Stealthily Managing Iptables Rules Remotely, Part 2

Get the WebProNews Newsletter:


[ Business]

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.

# 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 () {
    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_cmdn" 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 $commandn" 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 time 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…

Brian Hatch is Chief Hacker at href="http://www.onsight.com/">Onsight, Inc and author of
Hacking Linux Exposed
and Building Linux VPNs.
Brian can be reached at brian@hackinglinuxexposed.com.

Running Programs in Response to Sniffed DNS Packets – Stealthily Managing Iptables Rules Remotely, Part 2
Comments Off
Top Rated White Papers and Resources

Comments are closed.

  • Join for Access to Our Exclusive Web Tools
  • Sidebar Top
  • Sidebar Middle
  • Sign Up For The Free Newsletter
  • Sidebar Bottom