#!/usr/bin/perl -w # VIAGRA v1.0 # lewk@csh.rit.edu # This program was based off of the article: # http://www.securityfocus.com/infocus/1711 use strict; my $iface = "eth0"; my $editor = "vi"; my $backup = ""; my $restore = ""; print "VIAGRA v1.0 - Linux network hardening script\n"; print "Hardens your network, so you can keep it up longer!\n"; print "Usage: $0 [options]\n"; print "Options:\n -i interface Specifiy interface (default is eth0)\n"; print " -b file Backup original settings to file\n"; print " -r file Restore a previously backed up file\n"; print " -e editor Use specific edtor (default is vi)\n"; # Validate command line arguments if ( $#ARGV % 2 != 1 ) { print STDERR "Error: Invalid arguments\n"; exit(1); } for (my $i=0; $i <= $#ARGV; $i++) { $iface = $ARGV[$i+1] if ($ARGV[$i] eq "-i"); unless (-d "/proc/sys/net/ipv4/conf/$iface") { print STDERR "Invalid interface: $iface\n"; exit(1); } if ($ARGV[$i] eq "-b") { $backup = $ARGV[$i+1]; if (-e $backup) { print STDERR "Error: Backup file already exists\n"; exit(1); } } if ($ARGV[$i] eq "-r") { $restore = $ARGV[$i+1]; unless (-e $restore) { print STDERR "Error: Restore file does not exist\n"; exit(1); } } $editor = $ARGV[$i+1] if ($ARGV[$i] eq "-e"); } # Hardcoded pseudo files along with brief descriptions my %files = ( "icmp_echo_ignore_all", "When enabled, ignore all ICMP ECHO REQUEST (ping) packets. Does nothing " . "to actually increase security, but can hide you from ping sweeps, which " . "may prevent you from being port scanned. Nmap, for example, will not " . "scan unpingable hosts unless -P0 is specified. This will prevent normal " . "network connectivity tests, however.", "icmp_echo_ignore_broadcasts", "When enabled, ignore broadcast and multicast pings. It's a good idea to " . "ignore these to prevent you from becoming an inadvertent participant in " . "a distributed denial of service attack, such as Smurf.", "conf/$iface/accept_source_route", "When source routed packets are allowed, an attacker can forge the " . "source IP address of connections by explicitly saying how a packet " . "should be routed across the Internet. This could enable them to abuse " . "trust relationships or get around TCP Wrapper-style access lists. " . "There's no need for source routing on today's Internet.", "conf/$iface/rp_filter", "When enabled, if a packet comes in on one interface, but our response " . "would go out a different interface, drop the packet. Unnecessary on " . "hosts with only one interface, but remember, PPP and VPN connections " . "usually have their own interface, so it's a good idea to enable it " . "anyway. Can be a problem for routers on a network that has dynamically " . "changing routes. However on firewall/routers that are the single " . "connection between networks, this automatically provides spoofing " . "protection without network ACLs.", "conf/$iface/accept_redirects", "When you send a packet destined to a remote machine you usually send it " . "to a default router. If this machine sends an ICMP redirect, it lets " . "you know that there is a different router to which you should address " . "the packet for a better route, and your machine will send the packet " . "there instead. A cracker can use ICMP redirects to trick you into " . "sending your packets through a machine it controls to perform " . "man-in-the-middle attacks. This should certainly never be enabled on a " . "well configured router.", "conf/$iface/secure_redirects", "Honor ICMP redirects only when they come from a router that is " . "currently set up as a default gateway. Should only be enabled if you " . "have multiple routers on your network. If your network is fairly static " . "and stable, it's better to leave this disabled.", "conf/$iface/send_redirects", "If you're a router and there are alternate routes of which you should " . "inform your clients (you have multiple routers on your networks), " . "you'll want to enable this. If you have a stable network where hosts " . "already have the correct routes set up, this should not be necessary, " . "and it's never needed for non-routing hosts.", "ip_forward", "If you're a router this needs to be enabled. This applies to VPN " . "interfaces as well. If you do need to forward packets from one " . "interface to another, make sure you have appropriate kernel ACLs set " . "to allow only the traffic you want to forward.", "ipfrag_high_thresh", "The kernel needs to allocate memory to be able to reassemble " . "fragmented packets. Once this limit is reached, the kernel will start " . "discarding fragmented packets. Setting this too low or high can leave " . "you vulnerable to a denial of service attack. While under an attack of " . "many fragmented packets, a value too low will cause legitimate " . "fragmented packets to be dropped, a value too high can cause excessive " . "memory and CPU use to defragment attack packets.", "ipfrag_low_thresh", "Similar to ip_frag_high_thresh, the minimum amount of memory you want " . "to allow for fragment reassembly.", "ipfrag_time", "The number of seconds the kernel should keep IP fragments before " . "discarding them. Thirty seconds is usually a good time. Decrease this " . "if attackers are forging fragments and you'll be better able to service " . "legitimate connections.", "ip_always_defrag", "Always defragment fragmented packets before passing them along through " . "the firewall. Linux 2.4 and later kernels do not have this /proc entry, " . "defragmentation is turned on by default.", "tcp_max_orphans", "The number of local sockets that are no longer attached to a process " . "that will be maintained. These sockets are usually the result of " . "failed network connections, such as the FIN-WAIT state where the remote " . "end has not acknowledged the tear down of a TCP connection. After this " . "limit has been reached, orphaned connections are removed from the " . "kernel immediately. If your firewall is acting as a standard packet " . "filter, this variable should not come into play, but it is helpful on " . "connection endpoints such as Web servers. This variable is set at boot " . "time to a value appropriate to the amount of memory on your system.", "icmp_ratelimit", "This variable allows you to limit how frequently specified specified " . "ICMP packets are generated. icmp_ratelimit defines how many packets " . "that match the icmp_ratemask per jiffie (a unit of time, a 1/100th of a " . "second on most architectures) are allowed.", "icmp_ratemask", "The ratemask is a logical OR of all the ICMP codes you wish to rate " . "limit. (See /usr/include/linux/icmp.h for the actual values.) The " . "default mask includes destination unreachable, source quench, time " . "exceeded and parameter problem. If you increase the limit, you can slow " . "down or potentially confuse port scans, but you may inhibit legitimate " . "network error indicators.", "conf/$iface/log_martians", "Have the kernel send syslog messages when packets are received with " . "addresses that are illegal.", "neigh/$iface/locktime", "Reject ARP address changes if the existing entry is less than this many " . "jiffies old. If an attacker on your LAN uses ARP poisoning to perform a " . "man-in-the-middle attack, raising this variable can prevent ARP cache " . "thrashing.", "neigh/$iface/gc_stale_time", "How often in seconds to clean out old ARP entries and make a new ARP " . "request. Lower values will allow the server to more quickly adjust to " . "a valid IP migration (good) or an ARP poisoning attack (bad).", "conf/$iface/proxy_arp", "Reply to ARP requests if we have a route to the host in question. This " . "may be necessary in some firewall or VPN/router setups, but is " . "generally a bad idea on hosts.", "tcp_syncookies", "A very popular denial of service attack involves a cracker sending " . "many (possibly forged) SYN packets to your server, but never completing " . "the TCP three way handshake. This quickly uses up slots in the kernel's " . "half open queue, preventing legitimate connections from succeeding. " . "Since a connection does not need to be completed, there need be no " . "resources used on the attacking machine, so this is easy to perform and " . "maintain. If the tcp_syncookies variable is set (only available if " . "your kernel was compiled with CONFIG_SYNCOOKIES) then the kernel " . "handles TCP SYN packets normally until the queue is full, at which " . "point the SYN cookie functionality kicks in. SYN cookies work by not " . "using a SYN queue at all. Instead the kernel will reply to any SYN " . "packet with a SYN|ACK as normal, but it will present a " . "specially-crafted TCP sequence number that encodes the source and " . "destination IP address and port number and the time the packet was " . "sent. An attacker performing the SYN flood would never have gotten " . "this packet at all if they're spoofing, so they wouldn't respond. A " . "legitimate connection attempt would send the third packet of the three " . "way handshake which includes this sequence number, and the server can " . "verify that it must be in response to a valid SYN cookie and allows the " . "connection, even though there is no corresponding entry in the SYN queue." ); my $id = `whoami`; chomp($id); # Restore backed up settings if ($restore ne "") { print "[-] Restoring backup\n"; if ($id ne "root") { print STDERR "Error: You must be root to restore your settings\n"; exit(1); } open(IN, $restore) || die "Error: Cannot open $restore: $!\n"; foreach my $line ( ) { if ( $line =~ /^([^#\n ]*) -> (\d*)/ ) { my $val = $2; my $name = $1; $name =~ s/\./\//g; print "Restoring /proc/sys/net/ipv4/$name -> $val\n"; open(OUT, "> /proc/sys/net/ipv4/$name") || die "Error: Cannot open /proc/sys/net/ipv4/$name: $!\n"; print OUT "$val\n"; close(OUT); } } close(IN); print "[-] Settings restored\n"; exit(0); } print "[-] Loading previous settings\n"; print "[-] Creating backup file\n" if ($backup ne ""); open(BACKUP, "> $backup") if ($backup ne ""); open(OUT, "> .settings.tmp"); while ( my ($key, $value) = each(%files) ) { if (-e "/proc/sys/net/ipv4/$key") { open(IN, "/proc/sys/net/ipv4/$key"); my @data = ; print BACKUP "$key -> $data[0]" if ($backup ne ""); my $tmp = $key; $tmp =~ s/\//\./g; print OUT "# $value\n\nipv4.$tmp -> $data[0]\n"; close(IN); } } close(OUT); close(BACKUP) if ($backup ne ""); print "Press enter to launch editor...\n"; my $x = ; system("$editor .settings.tmp"); print "Press enter to save settings...\n"; $x = ; if ($id ne "root") { print STDERR "Error: You must be root to save your settings\n"; exit(1); } open(IN, ".settings.tmp"); foreach my $line ( ) { if ( $line =~ /^([^#\n ]*) -> (\d*)/ ) { my $val = $2; my $name = $1; $name =~ s/\./\//g; open(OUT, "> /proc/sys/net/$name"); print OUT "$val\n"; close(OUT); } } print "[-] Settings saved\n";