Thursday, May 14, 2009

Open Source Application Layer Firewall part 3

Now that the excitement of Secure360 has died down and we've shrugged off the effects of a phishing attack I finally have some time to work on the last few investigations that popped up recently and add another blog posting on my homebrew, open source application layer firewall.

In part 1 we talked about why an Application Layer firewall was necessary and why it was more secure than a simple Stateful Inspection Firewall. In part 2, we started setting up our lab environment by creating a web server with a simple (and insecure) php application that will need protecting. Here in part 3, we will begin creating our Application Layer firewall.

I'm not going to spend any time talking about the hardware that you want to use for something like this. It is largely dependent on your environment and what you're trying to do. It also isn't something that I am an expert on. There is a great write up here on selecting hardware for high network performance. I suggest you read that before you put something into production. What I will tell you is that for my example, I will be using a virtual machine with two NICs. One of them will be connected to a public network that people can access, and the other is connected to a private network and can only talk to the web server we created in part 2.

So the first step is to install OpenBSD on our firewall. Could I use linux? Of course I could, but OpenBSD has an excellent reputation for being proactively secure and auditing the crap out of their code. OpenBSD also comes with Apache already set up in a very secure chroot environment that we'll be taking advantage of. Even if you don't agree that OpenBSD is more secure than your linux flavor of choice, you will probably agree that running Apache in a chroot environment is more secure than not. And you will probably agree that setting up Aapche in a chroot environment is not trivial, so OpenBSD is the easiest choice as well. However, if I should find myself overflowing with some of that "time" stuff that I hear other people have, I might start documenting how to do this in linux as well.

I don't want to spend a great deal of time talking about the initial installation of the Operating System either. It is pretty easy to set up if you just follow the defaults. I use the whole disk for my operating system, and in this case I put everything in one partition. If I were doing this in production I might decide that I wanted /var to be in a separate partition so that I wouldn't have to worry about my machine crashing if log files fill up the whole hard drive. We wont have any users storing their crap on this server, so we don't really need to have /home or /usr on their own partitions. Also remember that in most cases you want to use the generic kernel, not the multiprocessor kernel.

Once the operating system is installed, follow these directions to get connected to an anonymous CVS server, and download the patch branch (# cd /usr; cvs checkout -P -rOPENBSD_4_4 src). Then follow these directions to compile and update your server. You are now patched and following stable.

Alright. You've got a patched server with two NICs, one of which is on your public network so clients can reach it, and the other is on the private network with our application server. Now we can start tuning this as a firewall.

For the rest of this HOWTO I'm going to try to work my way up the ISO model from layer to layer. We've just taken care of layers 1 and 2 by setting up our machines. Next we need to allow layer 3 routing. This is only marginally necessary. Since we are going to have proxy servers acting as go betweens, the operating system doesn't really need to route traffic. However, you never know when there is going to be some silly application that we wont be able to proxy and you'll have to route. So it's best to just do this now and never worry about it again.
Turn on IP forwarding:
# sysctl net.inet.ip.forwarding=1

Next, edit /etc/sysctl.conf and set net.inet.ip.forwarding=1 so that it will be set for you every time this machine boots. Congratulations, you now have a router!

Next up, let's work our way through some layer 3 and layer 4 technology, the pf firewall. Pf is a packet filter firewall that supports stateful packet inspection, NAT, and a whole host of other good stuff. It has built in support for anti-spoofing and scrubbing packets as they come in. It is every bit as capable as any other stateful inspection firewall. We're going to use PF to block most of the crap that will hit this firewall. I'm going to start with a very restrictive firewall rule set that only allows ping and ssh into the firewall. Edit /etc/pf.conf to read like this. Substitute your external interface for vic0.

# It is a good idea to not process stuff on loopback
set skip on lo

# Let's scrub our incoming traffic
scrub in

# The default deny rule
block in log on $ext_if
block out log on $ext_if

# This rule allows icmp echo in
pass in inet proto icmp all icmp-type echoreq

# This rule allows ssh in
pass in log on $ext_if proto tcp from any to port 22
The rule set scrubs incoming traffic and blocks everything going in and out. I was once chastised on the OpenBSD mailing list for forgetting that pf processes rules from the top down and runs the last rule to match the traffic. That's why our default deny needs to come first. The other two rules, the ones that allow ssh and icmp have an implicit "keep state" on the end of them. That's why we don't need to create a rule that allows the return traffic out. Now we can turn on pf by typing
# pfctl -e
You will also want pf to turn on when the firewall is booted so make sure you edit /etc/rc.conf and set pf=YES and pf_rules=/etc/pf.conf.

Now use pfctl to check the rules that are running and make sure everything looks right.
# pfctl -s rules
scrub in all fragment reassemble
block drop in log on vic0 all
block drop out log on vic0 all
pass in inet proto icmp all icmp-type echoreq keep state
pass in log on vic0 inet proto tcp from any to port = ssh flags S/SA keep state
Congratulations, you now have a stateful inspection firewall that doesn't allow anything to pass through to the private interface, but will let you ping and ssh into it.

If you're ready, you can move on to Part 4 now.


Anonymous said...

Coupla minor points.

OpenBSD is also very useful for lab and purpose-built applications due to the fact that it runs virtually no services by default. No service, doesn't matter if there's bugs, no exposure. I far prefer to enable services rather than dink around with figuring out how to *disable* them.

Second, a style point for OpenBSD systems in general, is that upgrades are much simpler if you don't muck with /etc/rc.conf. It's best to copy lines you want to change out of there and modify them in /etc/rc.conf.local, which overrides settings in rc.conf out of the box.


Black Fist said...

This is why I love the Internet. I put out my homebrew instructions on how to make something and in less than a day I have gotten advise on how to make it better. I hope this process will continue as the rest of the instructions go up.

Anonymous said...

I am really liking the tutorial you have submitted. I think that once you get to part 5 I will start tinkering with OpenBSD some more. I have great need for an application level firewall and this seems to be the cheapest option.

Thank you. :)