RSS Archive Contact Us Advertise

IT Management Begins With Security
SecurityProNews > Articles > Operating Systems > Running Programs In Response To Sniffed DNS Packets - Stealthily Managing Iptables Rules Remotely, Part 2
Search:
[ articles_operating_systems ]

Running Programs In Response To Sniffed DNS Packets - Stealthily Managing Iptables Rules Remotely, Part 2



Brian Hatch
Contributing Writer
2004-01-26

SecurityProNews RSS Feed SecurityProNews RSS Feed


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...



About the Author:
Brian Hatch is Chief Hacker at Onsight, Inc and author of Hacking Linux Exposed and Building Linux VPNs. Brian can be reached at brian@hackinglinuxexposed.com.



More articles_operating_systems Articles

SecurityProNews RSS Feed SecurityProNews RSS Feed


Get Your Site Submitted for Free in the World's Largest B2B Directory!

Email Address:
* URL:
*
*Indicates Mandatory Field

Terms & Conditions

iEntry Featured Services: Jayde Member Services | Forums | Freeware | Advertise with Us

Virus Warnings

Subscribe to
SecurityProNews FREE!



[ more newsletters ]

article resources
Search Articles:
[advanced search]

WebProWorld.com
Get in-touch with industry experts and leaders
Post your site for review by expert and peers
Ask Security, IT, Development and Design questions

Free Membership: Join Now!

Visit WebProWorld.com

Titan Quest Forum
The #1 Titan Quest forum
Halo 3 Forum
The best Halo, Halo 2, Halo 3 forum
Nintendo Wii
Nintendo Wii news and views
Mac Software
The best in OS X freeware
Graphics Forum
Your source for graphic tutorials
SecurityProNews.com | Breaking eBusiness News Get Your IT Questions Answered - Click Here SecurityProNews News Feeds