Tuesday, March 15, 2011

Run your favorite apps securely alongside an egress firewall with Iptables And Jailkit

In a perfect world the importance of egress or outbound firewall filtering would be common knowledge and implemented as a de facto standard alongside other common sense techniques such as anti-viruses, frequent patching, and non-admin user accounts and we would all live in a happy world free from many of the devastating worms and rootkits that constantly plague us.

Now instead of going off on a much long tangent on this, I will simply quote Brian Hatch who I think stated it quite aptly:
When your computer is compromised, you are no longer the innocent party trying to defend yourself, to other machines you have become the attacker. You owe it to others to make outbound attacks more difficult to the cracker or worms that have managed to get onto your machine.”
(Hacking Linux Exposed: Egress filtering for a healthier Internet - Brian Hatch)

With that out of the way, I think its only fair to concede that egress/outbound filtering, while important, can often come into conflict with a few of the common applications that we use on a daily basis on our  workstations.

One if the most popular applications that suffers from this is bittorrent software.  First off let me say that while this article uses the rtorrent peer to peer application as the example, the methods and approach here are relevant for any application that does not communicate in a predictable enough manner to create targeted iptables port rules.  In fact I can think of numerous penetration and security testing tools that this method could work well for (Nmap just to throw one out there).

Now I admit that the use of bittorrent software can introduce a host of security vulnerabilities even if used for legitimate purposes (and YES there are legitimate uses for bit-torrent), the fact is that it is widely used and trends show that this is not going to change anytime soon.

Too often though, I think otherwise very security minded individuals conclude that the risks of using peer to peer technologies just come with the territory and there is not much else that can be done aside from using DMZs and Virtual Machines, which have the extreme disadvantage of significantly increasing system resource utilization.

Fortunately, the there is a better and more targeted way to address this which helps to mitigate this risk.

First I think it is important to provide a bit more detailed summary of the issue I ran into while attempting to implement an egress filtering solution on my home desktop (I'm using Archlinux, but these methods should work with most Linux distributions).  The problem I ran into with bittorrent is that although it does use a set listening port, this port is used only by remote users connecting into your machine and is may not be the port used by your machine to initiate connections with remote users.  Also, each remote user has their own listening port which is not necessarily the same as yours.

This creates a situation where your outgoing source and destination ports are both random, leaving you without much of a way to effectively deploy an egress filtering firewall and still continue using your application.   Now there are numerous and well documented ways of getting around this by using firewall evasion techniques such as tunneling, there is another method that is often overlooked and not only does it get around this problem, it also gives you an extra layer of security.  This is particularly important when using programs such as bittorrent.

The basic idea behind this method involves running your bittorrent application in a chroot jail using a special user account.  While the security benefits of properly configured chroot jails are significant in and of themselves (and I stress properly configured), running them as a special user allows you to utilize iptables match by user feature.  What this does, is allow us to implement a “default drop” outgoing firewall rule and add special exceptions for certain users.

So the ultimate solution here is to construct a user who operates exclusively within a chroot jail that allows access to the program needed and nothing else (not even a command shell) and then use the iptables match by owner feature to allow this user and this user only access to the ports needed by the application.  This will let you continue to use your application while at the same time significantly reducing the exposed vulnerability landscape on your machines.

In this tutorial Im going to be using the ncurses based bittorrent client rtorrent as the example since that is what I use as it allows me to easily manage my torrents remotely wherever I happen to be using screen and ssh.
More information about rtorrent can be found at http://libtorrent.rakshasa.no/

To create and manage the chroot environment I will be using the jailkit utilities.  The jailkit homepage describes the suite as “a set of utilities to limit user accounts to specific files using chroot() and or specific commands.”

Using jailkit greatly simplifies the process of setting up a chroot and can help to prevent some bad chroot mis-configurations.  I suppose this is a good time to issue the standard chroot disclaimer:
Warning! An improperly set up a chroot environment can actually create a security hole!

More information on jailkit as well as documentation for many of its other features can me found at  http://olivier.sessink.nl/jailkit/ 
In particular, I strongly recommend reading the “SECURITY CONSIDERATIONS” section on the homepage for what you should NOT do while setting up your chroot environment. Its short, so read it.

Lastly, this tutorial assumes you have an iptables firewall in place as well as CONFIG_NETFILTER_XT_MATCH_OWNER kernel option either compiled into your kernel or as a module.

Quick word of warning before I get into the commands:  Due to the small page space Google actually gives to the blog, commands may get word wrapped.  Commands will be separated from each other with extra white space to avoid confusion. I'll be looking for a better medium for my articles soon.


Now on to the actual setup

To verify whether the match owner netfilter module is running, do
lsmod | grep xt_owner
If the output indicates that the module is loaded and running, you're good to go

The next thing to do is get jailkit installed on your machine.
There happened to be a jailkit package already available in the Archlinux AUR repository, but I am aware that some distributions may not have one (Ubuntu for instance).  In that case the source code may downloaded from the jailkit website given above.

Once jailkit is installed and the user match iptables module is running, we can start creating our chroot jail.

First thing, we need to actually make the jail. I call mine “rtor” but you can call it whatever you like, although I would recommend not calling it by the same name as the user that will be operating inside of it.
mkdir /home/rtor
make it owned by root
chown root:root /home/rtor
then
chmod 0755 /home/rtor
Now we need to create the user and group account for the application we will be using.  I use id 1010 for both user and group but you can use whatever id as long as its not already taken
groupadd -g 1010 rtorrent
usermod -g rtorrent rtorrent
Now
adduser rtorrent
Obviously, lets use a good password here

We need to tell jailkit what capabilities our jail needs.  For rtorrent I used:
jk_init -v -j /home/rtor netbasics limitedshell terminfo
Others can be found in /etc/jailkit/jk_init.ini
You should see numerous files needed for netbasics limitedshell and terminfo being copied over into your chroot jail

Now that the jail is set up, you need to jail your newly created user
jk_jailuser -m -j /home/rtor rtorrent
This will move the home directory of the user into the chroot jail. The new path should be similar to /home/rtor/home/rtorrent

Using Archlinux I had an issue with the way it copied over the /etc/passwd file and ended up with some values cut out of the users passwd entry.  I suggest checking the newly created /home/rtor/etc/passwd and group file to make sure the entries are sane.
The passwd file should look similar to
rtorrent:x:1010:1010::/home/rtor/./home/rtorrent:/usr/sbin/jk_lsh
Now we need to copy over application we want the user to access.
To do this we much add an entry into the /etc/jailkit/jk_init.ini file pertaining to that application
vi /etc/jailkit/jk_init.ini
For rtorrent, mine looks like this
[rtorrent]
comment = rtorrent
paths = /usr/bin/rtorrent
now it can be copied over simply with
jk_init -v -j /home/rtor rtorrent 
This copies the program over as well as any of the libraries the program requires to function

Now whats nice about jailkit, is that just having the rtorrent libraries and binaries installed into the chroot isnt enough to actually let the user run the application.

Jailkit has an added configuration file that specifies what binaries the user is allowed to use.  This way if an attacker manages to break into your chroot she is severely restricted by what she is allowed to run.  To allow the user to actually run rtorrent we must add a section for the user in the /home/rtor/etc/jailkit/jk_lsh.ini file

mine looks like this:
[rtorrent]
paths= /usr/lib/, /usr/bin/
executables= usr/bin/rtorrent
Finally, in order to allow the user rtorrent to attach to the terminal, we must edit
/etc/jailkit/jk_chrootsh.ini and add
[rtorrent]
env= TERM
If you will be using X apps withing the jail make sure include the DISPLAY, XAUTHORITY variables as well

Now Restart jk_socketd to make sure log messages are transferred
killall jk_socketd
jk_socketd
Now, theoretically all we should need to do to run the application is to su to the user with the -c switch to instruct it to just run that one command (remember, we are not allowing the user a shell so this is the only way to start the program).
su - rtorrent -c rtorrent
Of course theory is theory and it turns out rtorrent needs a few extra things to get up and running.
Specifically, a .session folder as well as the .rtorrent.rc config file.
We need to copy these into the users home directory within the jail and turn them over to the rtorrent user.
So as root we need to
mkdir /home/rtor/home/rtorrent/.session 
chown rtorrent:rtorrent /home/rtor/home/rtorrent/.session 
cp /<path/to/your/.rtorrent.rc> /home/rtor/home/rtorrent 
chown rtorrent:rtorrent /home/rtor/home/rtorrent/.rtorrent.rc
If you do not have an .rtorrent.rc file yet, you can get the example one from http://libtorrent.rakshasa.no/browser/trunk/rtorrent/doc/rtorrent.rc#latest and modify it for your needs

now we can try and run the program to verify that its working.
su - rtorrent -c rtorrent
If you are having any problems or you find that you are not switching users, you might want to take a look in your /var/log/auth.log to see if there were any permission errors and /var/log/daemon.log to see if there were any jailkit daemon errors.

Now once you've got this all working, you should be able to run
ps aux | grep rtorrent 
and see a line showing rtorrent running as user rtorrent

Now if thats its working, actually setting the exceptions to your iptables firewall is easy.
This assumes that you have egress/outbound filtering in default drop mode. Meaning there should be a line in the beginning of your firewall rule set that looks like this:
$IPTABLES -P OUTPUT DROP
To add the exceptions we add
$IPTABLES -A OUTPUT -p tcp --sport 1024:65535 -m owner --uid-owner rtorrent -j ACCEPT
to the output chain and
$IPTABLES -A INPUT -p tcp --dport 55555 -j ACCEPT
to the input chain.
Of course set the port number to be your application's listening port. Unfortunately, iptables does not have a feature to specify the incoming destination user so this rule applies globally.
You want to be sure that the packets that are accepted by port 55555 are actually valid. All iptables rules should have something similar to this for both the INPUT and OUTPUT chain to enforce this
$IPTABLES -A INPUT -m state --state INVALID -j DROP$IPTABLES -A OUTPUT -m state --state INVALID -j DROP
Also, if you need to use distributed hash tables (DHT) or some other UDP based peer exchange technologies to find peers (such as pirate bay and other trackerless bittorrent methods) you will need to include similar rules for UDP based on the UDP port set in your torrent application.

Now update the firewall and you should have a proper egress firewall which allows only your one application user to use the ports needed to connect out and since this user is strictly forbidden from using any other executable, you are able to continue using the application while significantly reducing the possibility of an attacker maliciously controlling your machine.

Unfortunately this nifty setup does leave you with one small problem: getting the torrents in and the downloads out.
Well, theres not really any other way aside from using root to do this.
But considering the added security benefits, this is pretty fair trade off.
as root:
mv ./<torrent> /home/rtor/home/rtorrent/ 
chmod rtorrent:rtorrent /home/rtor/home/rtorrent/<torrent
 now open the torrent normally and when the download finishes
mv /home/rtor/home/rtorrent/<download> /home/<yournormaluser>/ 
chmod <yournormaluser>:<yournormaluser> /home/<yournormaluser>/<download>
And thats it!

Lastly, you may have been wondering: “Well what happens when the new version of the program comes out? Does that mean I need to do this all over again to use it?”
Luckily, the answer is no.  The developers over at jailkit already thought of this and included with the jailkit program is a nifty little tool called jk_update
Simply running
jk_update -j <jail>
will check all files in the jail for updates and copy them over.
The documentation page on jk_update states:
jk_update will compare the files in a jail with the corresponding files on the real system. If the corresponding file on the real system is newer, and the file on the real system is different, the file from the real system will be copied to the jail including any required libraries just like jk_cp would do. Files that do not exist on the real system will be deleted in the jail.” (http://olivier.sessink.nl/jailkit/jk_update.8.html)

Pay particular attention to that last sentence!  Read it twice.  Now read it again.
By default jk_update will scan /usr, /bin, /opt, and /lib for updates.
So make sure that if you have added any scripts to the jail that you add special skip rules.  An explanation of how to do this is given on the previously mentioned jk_update documentation page

Well hopefully if you've gotten this far everything is up and running.  Like I said, rtorrent is just one example of an application that can be secured in this manner.  This is actually a fairly eloquent solution that can be applied to numerous applications on your egress filtering protected machines.

Of course questions, comments, suggestions are welcome. If you found this helpful let me know and be sure to thank the authors of these programs for their excellent work!

Introduction

I suppose I should introduce myself. Im a Linux and IT security hobbyist.  I hold a degree in Economics but I'm looking to get into the IT security field. I'm LPIC Level 1 certified and hope to be security+ certified in a month or so.
I've decided to start this blog since Ive been finding myself adding tutorials to open source wikis more and more lately and would like to have my own place to aggregate some of them as well as to start documenting some of my other small Linux and security related projects for reference as well as to put them out there for others to benefit and comment on.  Hopefully they will be of use to someone and maybe I'll even get some good suggestions and comments.  I am by no means an expert on everything posted so by all means feel free to school/correct/rant on anything here.

Topics will probably include programs such as tor, i2p, screen, iptables, fwknop and so on.  I generally stick to the command line and use Archlinux, Gentoo, and Debian.

As for the name, its near 5am and the Melvins - Night Goat just happened to be playing and I figured its as good a name as any other so I ran with it. Besides, that song owns.

At some point I'll get an actual blog/site set up on my own server, but until then this will do.
Alright, now for a post thats actually useful.