Egress Filtering? What - do we have a bird problem?

Published: 2014-07-11
Last Updated: 2014-07-11 14:48:02 UTC
by Rob VandenBrink (Version: 1)
5 comment(s)

One of the major tools that we have in our arsenal to control malware is outbound filtering at firewalls and other network "choke points".  
Over the years, it's become obvious that "enumerating badness" on the internet is next to impossible, it's generally much easier to enumerate "known good" traffic, and simply deny the rest as bad or at least suspect.  Often the management response is "we trust our people", but that's not really the point.  While maybe you can trust all of your people, you can't trust the malware they may have, or all the links they might click.  But let's be honest, it's likely that you can't trust all of your people to never install a bittorrent client or other higher-risk program.

So, as they say in the circus - "This Way to the Egress!"

An egress filter is generally put on your firewall, allowing known good traffic, and denying everything else outbound (and logging those attempts - hopefully you're monitoring your logs right?).  So, how do you go about setting up an egress filter?  You can't just list 10 protocols that you know are good and deny the rest - that's a good way to find out what OTHER protocols your business requires when you break those business processes - in other words, that's the hard way to do this.

We'll use the approach in the previous story to figure out what exactly we're running through the firewall, so we can then make go/no-go decisions about each one.

We can take a big chunk out of this by:
allowing DNS only from DNS Servers
Allow mail only from mail servers (permitted mail servers)
allow browser web traffic (either just from a proxy, or from all permitted workstations, depending on the organization)

So we can list the tcp protocols in play with:
D:\syslog\archive\2014-07-03>type SyslogCatchAll.txt | grep outbound | grep TCP | sed s/\t/" "/g | cut -d " " -f 12 | cut -d "/" -f 2 | grep -v 80 | grep -v 443  | grep -v 25 | sort | uniq -c | sort /R

This gives us the following output, listing the remaining protocols, in descending order.

    118 22
     81 1935
     80 8080
     79 993
     68 445
     66 843
     39 5228
     34 53
     28 5223
      4 52223
      3 135
      2 52165
      1 52222
      1 40009

Hmm - that gives us something to work with.  We can use the techniques covered in yesterday's story ( to dig deeper into these.

It turns out that the 135 and 445 traffic was drive maps through an inbound vpn session - no problem there.
The tcp/22 was sftp outbound - two business processes involving a transfer of financial information.  
For one, we allowed the outbound from the designated transfer host.  for the other, we allowed the outbound traffic to the designated destination.  Then denied 22 from others.
The "8080" protocol was an application (not a browser) using an outside proxy server.  This could as easily have been malware using a proxy, or someone using an "anonymizer" proxy or a "make it look like I'm in the US" proxy (we get some of that in Canada).

.. and so on.

Of course, you'll have to do the same for UDP also, and also the other protocols that aren't either tcp or udp.

So you'll have a list (in pseudo english / cisco speak) like:

ip access list extended ACL_INSIDE_OUTBOUND
permit dns from known dns servers, to the permitted dns forwarders only (we turned root hints off at the servers)
deny dns from anything else, and log the attempt
permit mail from the mail servers
deny mail from anything else, and log the attempt
permit http
permit https
permit tcp/22 from the one transfer client to anything
permit tcp/22 from anyone else to the second transfer server
deny tcp/22 from anything to anything else, and log the attempt
deny ip protocol 41 and log the attempt  (remember from yesterday that this is IPv6 Teredo tunneling)
 and so on
permit ip any any log

The last line is the critical one.  With that entry, you can then use the log mining techniques we've been discussing to mine the logs for just the entries that trigger that last line - the "permit ip any any log" line.  Eventually, you'll find that after whittling down the protocol list, you'll have a shorter and shorter list each day. At some point, you'll need to change that last line to a "deny any any log" at the bottom of the list.  Be sure that you've gone through a month end, and maybe even a year end before you add that last line. (the year end might be stretching it, unless your accounting year matches up with this project for you)

In answer to "we trust our people" - Those high port numbers in our initial list turned out to be bittorrent traffic - the giveaway was that it was from odd high ports to other odd high ports.  After digging through the logs a bit more, we identified the IP address that was running the protocol, and thought we'd be dealing with one of those uncomfortable "people problems".  Even better though - the source of this traffic turned out to be in the server IP range.  After some digging, it turned out to be a QNAP NAS that was used to store laptop images.  After cracking the manual, we found this box shared everything out via bittorrent via default.  At that point we were both saying - really?  This whole "collaboration / sharing" thing can go to far, and this was in fact too far!  Who's idea was it to make these NAS devices a "share all my data with the world" devices?

So maybe you can trust your people, but you can't trust them to read the manual !  And you can't trust them to always think about security before they plug new gear in.

Egress filters aren't 100% effective, but the are a critical part of your "defense in depth" strategy.  For instance, lots of malware (and bittorent clients and other apps too) will "hunt" until they find an open outbound port - so you'll often see them using ports like tcp/80, 443 or udp/53.  But with a proper egress filter, you'll quite often catch even this "port hunting" behaviour in the logs also.  If you are able to stand up a proxy server, often it's possible to deny almost all direct communication from the workstations, but really, that's just moving the same problem to the proxy server.

In newer architectures (those NGFW's we're all talking about), you'll find much more effective controls, but the concepts of filtering outbound traffic, and how to implement this, remain very much the same.  For instance, at home I've got a time-based ACL that allows my kid to play minecraft only in certain time windows (what can I say, it was fun to code that up). 

If you are doing egress filtering, what have you found in the process of putting them in?  What's the coolest thing you've caught after you've had it in place?   Let us know in our comment form.

If you're not doing egress filtering, why not?

Rob VandenBrink

Keywords: egress filter
5 comment(s)


The link to the image file is via HTTP and is generating a "mixed content" warning in the browser.
*nix purist back again

cat SyslogCatchAll.txt | grep -E "outbound|TCP" | sed s/\t//g | awk -v FS='/' 'sum = $12; $0=$2{print $0}' | grep -Ev "80|443|25" | sort | uniq -c | sort -rn

due to a comment from the last post according to the times command the difference between tr and sed is to minimal to be consequential, at least on a Intel i5 running Arch Linux
Why are you using the "type" command ?

grep works fine on files, from man grep :

grep, egrep, fgrep - print lines matching a pattern

grep [options] PATTERN [FILE...]
grep [options] [-e PATTERN | -f FILE] [FILE...]
Hi *nix purist, AWK purist here. :) I think this code will do it was well.

/outbound/ && /TCP/ {
split($12, sock, "/")
if (sock[2] !~ /^(25|80|443)$/)

for (i in pnum)
print pnum[i], i | "sort -rn"
Yes, I know you can use "grep" directly :)

I used "type" for two reasons. In this case, the host I was working with was a Windows host. I had a few binaries from GNUtils to work with (sed, cut, grep), but had not received permission to install the entire suite, and had also not gotten permission to install Microsoft's Tools for Unix. I still could have started the command with grep, but see reason 2

The second purpose of this exercise was to educate the client - - in his mindset, the command line if foreign territory already, I was trying to keep things simple as vanilla as possible for him. Starting the exercise by typing the file (to show how much data there is to sift through), then progressively filtering it illustrated the point to him.

Third reason (ok, 3 reasons) - on a consulting gig, in many cases when you have the answer you are done. Making the cli "more better" doesn't actually accomplish anything for the client, from their perspective it just burns time and money. In this case, perfect really is the enemy of good - and done quickest (correctly) really is the best solution.

Thanks for your post, I'm hoping that sheds some light - if you've found something cool by filtering outbound traffic we'd love to hear about it!

Diary Archives