% vim:tw=110:tabstop=4:shiftwidth=4 %\documentclass[11pt]{report} \documentclass[10pt,twocolumn]{article} % Specify what packages we're using \usepackage{times} \usepackage{textcomp} \usepackage{lastpage} \usepackage{latexsym} \usepackage{amssymb} \usepackage{listings} \usepackage[bottom, multiple, marginal, norule]{footmisc} \usepackage[dvips]{graphicx} \usepackage[colorlinks, bookmarks, dvips]{hyperref} \usepackage{fancyvrb} \usepackage[footnotesize,bf]{caption2} %\usepackage[letterpaper,lmargin=1in,rmargin=1in,bottom=.35in,top=.35in,headsep=.6in]{geometry} \usepackage{longtable} % Include Tillman's document styling %\usepackage{tjh} % Use the geometry package and fiddle with margins % Don't mess with this :-P \usepackage[letterpaper,lmargin=.65in,rmargin=.65in,bottom=.5in,top=.5in,headsep=.6in]{geometry} % with 7 mm gutter \setlength{\columnsep}{.6cm} % Separate footnotes (if present) from the margins by a reasonable amount \setlength{\captionmargin}{.5in} % Set the footnote indent \setlength{\footnotemargin}{0.25em} % Manually set the footnote separation from the body text by redefining what footnoterule means % (Note that this overrides the 'norule' in the footmisc options) %\renewcommand\footnoterule{% % \vskip 0.25in % \hrule\@width.4\columnwidth} % Set our standard unit of measure \setlength{\unitlength}{1in} % Change the behaviour of floats to something a little more liberal \renewcommand\floatpagefraction{.9} \renewcommand\topfraction{.9} \renewcommand\bottomfraction{.9} \renewcommand\textfraction{.01} \setcounter{totalnumber}{50} \setcounter{topnumber}{50} \setcounter{bottomnumber}{50} % Create our custom config-file printing environment % Use this for anything you want to print out "code style" % like so: \begin{Verbatim} blah \end{Verbatim} % Note: {Verbatim} is case sensitive! Capital V, please. % (this is based on the fancyvrb package) \RecustomVerbatimEnvironment{Verbatim}{Verbatim}{fontsize=\scriptsize,frame=lines,obeytabs=true,tabsize=4} \fvset{fontsize=\scriptsize,frame=lines,obeytabs=trie,tabsize=4} % For "little" code snippets (like URLs or email address), refine the + % symbol to act as a formatting delimiter,.i.e. +code+ would be formatted % in a way to mark it as a code snippet. \DefineShortVerb{\+} % Specify the document's meta information \title{Automating the use of dshield.org's Top 10 list} \author{\textsl{Tillman Hodgson}} \date{Initial Revision: January 30, 2003\\ Revision date: \today} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is where the content begins ... \begin{document} % Create our standard title out of our document meta information \maketitle %{ % \sffamily \tableofcontents % \listoftables % \listoffigures %} % Define how we want our paragraphs to look % Note: This is done after the TOC so that it doesn't affect how % the TOC looks \setlength{\parindent}{0pt} \setlength{\parskip}{1.5ex plus 0.2ex minus 0.1ex} % Set up our page style for future pages (beyond the TOC) \pagestyle{headings} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Background} \subsection{What is Dshield.org?} DShield.org was officially launched end of November 2000. Since then, it has grown to be a dominating attack correlation engine with worldwide coverage. While initially run as a volunteer effort, DShield.org has recently received support from the SANS Institute. DShield.org is the .Distributed Intrusion Detection System,. an attempt to collect data about cracker activity from all over the Internet. This IDS data is cataloged and summarized for use by the general public. It can be used to discover trends in activity and prepare better firewall rules. DShield is regularly used by the media to cover current security events. Analysis provided by DShield has been used in the early detection of several worms, like ``Ramen'', ``Code Red'', ``Leaves'', ``SQL Snake'' and more. It is the goal of DShield to allow access to its correlated information to the public at no charge to raise awareness and provide accurate and current snapshots of Internet attacks. \subsection{How does the Top 10 list work?} Dshield.org collects information that is voluntarily supplied by many Internet-connected organizations around the world. This information is consolidated and tracked over long periods of time. If a particular IP address is reported as being the source of a large number of attacks by a significant number of Dshield.org users\footnote{Thus preventing spoofed reports}, and it continues to do so over at least 5 days, it will be investigated by hand and might make the Top 10 Most Wanted list. Dshield.org also picks the strongest cases from the logs reported to it and investigations it undertakes and uses these to follow up with the ISP of the attacking IP address. This often gets a much quicker and more thorough result than individual targets attempting to complain to the ISP. \subsection{What does the Top 10 list look like?} The Top 10 list is viewable on the web at +http://www.dshield.org/top10.html+. As of 2:00PM on January 28, 2003 the Top 10 list was: \begin{center} \begin{tabular}{lll} & \# of lines & \\ & implicating & \# of hosts \\ IP Address & this attacker & attacked \\ \hline 202.172.234.8 & 656422 & 229558 \\ 194.17.211.132 & 234538 & 101151 \\ 217.160.110.151 & 185033 & 54375 \\ 138.121.23.4 & 501396 & 113941 \\ 157.169.10.110 & 87851 & 85841 \\ 213.33.62.110 & 82398 & 79049 \\ 211.199.143.9 & 74490 & 37847 \\ 218.30.21.40 & 381591 & 174389 \\ 208.190.30.203 & 249890 & 148779 \\ 195.218.135.218 & 177059 & 148896 \\ \end{tabular} \end{center} As the extreme numbers demonstrate, these IP addresses have been proven unfriendly. It is extremely unlikely that an IP address will end up on the Top 10 list by mistake. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Automatically blocking the Top 10} \subsection{The idea} That the security of a firewall be increased by pro-actively blocking traffic from IP addresses that have convincingly proven themselves to be hostile by being listed on the DShield.org Top 10 list. \subsection{The benefits} Known hostile IP addresses will not be able to access your network through channels that are normally allowed. For example: email, web browsing, etc. This prevents exploits or denial of service attacks from occurring by preventing the hostile IP from contacting \emph{any} network service. \subsection{The risks} The major risk is that the IP address of a partner or convenient Internet resource may end on the Top 10 list. Due to the checks that DShield employs to prevent this from happening, it is unlikely that this would ever occur. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Using IPF for automation} This method of automation uses IPF, +fetch+, +cron+ and a one-line +awk+ script. It was implemented on FreeBSD 4.7-STABLE, but could probably be easily implemented on any other Unix-ish system that runs IPF. \subsection{Obtaining the Top 10 list} A simple cron job performs the work of obtaining the Top 10 list (via +fetch+\footnote{wget would probably also work, but fetch is native to FreeBSD}), massaging it to IPF rules format, and writing it to a file in +/usr/local/etc+. \begin{Verbatim} #min hour mday month wday who command 44 6,12 * * * root fetch -q -o - \ http://feeds.dshield.org/top10-2.txt | awk '{print \ "block in log quick on rl1 from", $1 "/32 to any \ group 121"}' > /usr/local/etc/ipf.top10.rules \end{Verbatim} Note that this is one line, and backslashes signify that the line continues. I chose two runs a day (in case one run fails for whatever reason), and I run it at 44 minutes after the hour---please select a different minute to run on so that +dshield.org+ isn't hit by spikes in traffic. The result of this cron job is a file, +/usr/local/etc/ipf.top10.rules+, that looks like this: \begin{Verbatim} block in log quick on rl1 from 202.172.234.8/32 to any group 121 block in log quick on rl1 from 194.17.211.132/32 to any group 121 block in log quick on rl1 from 217.160.110.151/32 to any group 121 block in log quick on rl1 from 213.33.62.1/32 to any group 121 block in log quick on rl1 from 157.169.10.11/32 to any group 121 block in log quick on rl1 from 216.205.94.116/32 to any group 121 block in log quick on rl1 from 66.250.140.10/32 to any group 121 block in log quick on rl1 from 208.190.30.203/32 to any group 121 block in log quick on rl1 from 218.30.21.40/32 to any group 121 block in log quick on rl1 from 24.159.31.102/32 to any group 121 \end{Verbatim} This is a nicely formed IPF ruleset. Note that group 121 is specified, this is important to the integration with IPF. \subsection{Modifying your IPF rules} In order to allow rules to be inserted into the middle of the ruleset, we need to use the ``groups'' feature of IPF. The following +/etc/ipf.rules+ skeleton can be used to put groups into effect. Note that you you need to put your normal IPF rules in, under group 120. \begin{Verbatim} ############################################################ ### Notes: ### * The internal interface is simply trusted in/out ### * Group 100 is for the external interface ### * 110 is outgoing traffic originating with this host ### * 120 is incoming traffic destined for this host ### * 121 is the black-list for incoming traffic ### ### Group 121 is loaded by group 120 first, so additions to ### 121 will actually end up in the middle of the rules, ### which is very useful. ############################################################ ############################################################ # Inside Interface ############################################################ pass in quick on rl0 all keep state pass out quick on rl0 all keep state ############################################################ # Group 100 (External Interface) ############################################################ block out log body on rl1 all head 110 block in log body on rl1 all head 120 ############################################################ # Group 110 (External Interface, outgoing) ############################################################ #----------------------------------------------------------- # Allow out all TCP, UDP, and ICMP traffic & keep state on it # so that it's allowed back in automatically #----------------------------------------------------------- pass out quick on rl1 proto tcp from 24.72.10.212/32 \ to any keep state group 110 pass out quick on rl1 proto udp from 24.72.10.212/32 \ to any keep state group 110 pass out quick on rl1 proto icmp from 24.72.10.212/32 to \ any keep state group 110 ############################################################ # Group 120 (External Interface, incoming) ############################################################ #----------------------------------------------------------- # Block the black-listed IPs group. Note that this means # that group 121 occurs /before/ the rest of group 120. We # also don't log it - we know they're bad already. #----------------------------------------------------------- block in on rl1 all head 121 group 120 #----------------------------------------------------------- # All your other normal firewall rules go here #----------------------------------------------------------- # your rules here ... #----------------------------------------------------------- # Finally, block politely all other traffic # Note that the default block policy for this group is thus # not reached for TCP or UDP connections #----------------------------------------------------------- block return-rst in log body quick on rl1 proto tcp \ from any to any group 120 block return-icmp-as-dest(port-unr) in log body quick \ on rl1 proto udp from any to any group 120 ############################################################ # Group 121 (External Interface, black-listed incoming) ############################################################ #----------------------------------------------------------- # This group is seperate, see /usr/local/etc/ipf.rules #----------------------------------------------------------- \end{Verbatim} \subsection{Updating the IPF ruleset with cron} This should be done at a time when your other daily cron jobs have already finished but before there is any significant Internet traffic. This is because touching the firewall rules has the potential (however unlikely) for causing trouble and minimizing the potential impact migitates this somewhat. Somewhere around 5:00AM seems reasonable for many people. \begin{Verbatim} #min hour mday month wday who command 00 5 * * * root ipf -f \ /usr/local/etc/ipf.top10.rules \end{Verbatim} This cron job loads the rules in +/usr/local/etc/ipf.top10.rules+ into the current IPF ruleset without first flushing the ruleset. Normally, this would append the rules to the end of the ruleset, which is likely after your +pass+ rules would have already permitted access. However, these rules are in group 121 which are explicitly checked before any +pass+ rules. Effectively, this inserts the rules into the middle of the ruleset. \subsection{Testing the rules} To see the ``hit count'' for your rules, try something like +ipfstat -hin | grep "group 121"+. This lists all the rules in group 121 with the first field being a count of how many times that rule has been ``hit'' by a packet. \subsection{Temporarily adding rules} Group 121 now becomes useful for temporarily blocking access to hostile hosts. Simply echo an IPF rule that specifies group 121 to the +ipf+ command to have to take effect. For example: \begin{Verbatim} echo "block in quick from 1.2.3.4/32 to any group 121" \ | ipf -f - \end{Verbatim} \subsection{What about duplicates?} Duplicates don't cause a problem as IPF will automate discard them. You may see an error message (+#:ioctl(add/insert rule): File exists+\footnote{Where \# is the rule number that was duplicated}), but everything will work correctly. \subsection{What about removing old rules?} You can use the +-r+ option with +ipf+ to remove a rule. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \end{document}