First, start with a typical install. If you are not familiar with this process, you should be reading the handbook on installation before consulting this article.

In this chapter we'll talk about the lockdown procedures of a freebsd machine. This article assumes the end user has a general level of familarity with FreeBSD, and unix, in particular, file permissions, kernel configuration, file editing, and basic ssh usage.

In the second chapter we'll go depth with suid bits, file attributes and daemon configuration. In the 3rd chapter we'll talk about openssl, ipsec and encryption in general, including GPG/PGP and TCFS.

First off install NMAP. It's a very useful tool, and we'll be using it a bit later on to check on security and on packet filtering.

In order to install NMAP you can use the ports, or if you wish simply use the packages.# pkg_add -r nmap

Let me explain, nmap is a portscanning util. You can use it throughout this article as you progress through the various steps to check on your machines remote security. While nmap is an excellent tool, it does not give you a picture of local security. NMAP'ing your servers every so often, even after they are locked down, is usually a good idea. If only to check if additional services have been added or to see if firewall rules have been modified.

Another tool I would strongly suggest is nessus. Nessus is an excellent method for checking remote host security, and is in fact used by many professional auditors for that very purpose. Nessus is also in the ports collection and it can be found under "security/nessus".

Syslog Behavior

Next lets move to one of the most important areas of security: logging. While FreeBSD is one of the most secure operating systems around, it does have some drawbacks in the area of logging. By default things donīt really log to very useful places.

Lets edit /etc/syslog.conf and make some changes.

I usually modify my security.* /var/log/security line to read like this.

security.*;auth.info /var/log/security

The reasoning behind this is simple, by default ssh logins to the logging facility auth. You can, if you like, make this a separate log file using the following in your syslog.conf instead of the above.

auth.info /var/log/auth

If you prefer, you can create another file created. However, if you do this, make sure you update /etc/newsyslog.conf to include it, for example.

/var/log/auth 600 10 100 * Z

It's also a good idea to modify newsyslog.conf to fix some of the world readable permissions on some log files: for example maillog and messages log. I usually change these to 600, so that they are not readable by the world. I really donīt need to have them world readable, so I modify the 644 value to 600 in the newsyslog.conf file.

/var/log/messages 600 5 100 * Z

/var/log/maillog 600 7 * @T00 Z

Let us return briefly to syslog. I do not like how important data is written to console, since I plan on managing servers remotely, with respect to desktops I plan on using the console to edit system files. The log reporting to console I find is very distracting when modifying system files or doing any sort of programming. So here's how to prevent it. Comment out these lines.

# *.err;kern.debug;auth.notice;mail.crit /dev/console

# *.err root

# *.notice;news.err root

# *.alert root

In the case of workstations or desktops, you might actually want to read information easily. Please note the following is probably not a good idea for servers or publically accessible machines as it could lead to a compromise of information.

*.* /dev/ttyvb

The above will cause all logged information to be dumped onto virtual terminal B, which is ALT-F12. It's very useful for debugging purposes, and it's the setting I use on my workstation/sandbox machine. If you do this however you may want to look at using "security/vlock" to lock your console when you are away from the keyboard.

Finally to prevent users from reading these files you'll want to issue the following commands. The reasoning is you dont want to give people any additional information, that they might be able to use against you.

# chmod 600 /etc/syslog.conf

# chmod 600 /etc/newsyslog.conf

SSH Configuration

Now, I think we have logging pretty much covered. Make sure however to test it out fully on your own machine. We are now ready to move onto SSH itself. Since SSH will be your primary remote administrator tool and one of the few services running, you should pay special attention when locking it down. SSH itself can lead to security breach as some of us have seen in the past.

The SSHD control file is /etc/ssh/sshd_config. If your not planning on accessing your server or box remotely with anything using SSH protocol 1, then I would recommend disabling it completely. It's generally not considered as secure as protocol 2, In any event you should not be offering any services that you do not expressly need. Likewise it will stop someone from hijacking the startup session and downgrading you to protocol 1 by modifying the packet carrying the version banner. This could in theory be done to force communication using the weaker ssh 1 protocol.

Uncomment the Protocol 2,1 line and change it to read

Protocol 2

Secondly, SSH takes up alot of memory when it's being run and it's a commonly dos'ed service. Since each connection takes up a good chunk of memory. FreeBSD by default has a line called "MaxStartups". Personally I think this is rather high, and unless your running a shell box the values can be lower greatly.

MaxStartups 5:50:10

Seems far more reasonable, unless you're going to have alot of people administrating this system, or you're offering shell services. Even then, this is a rather healthy value for most shell providers. Remember MaxStartups does not mean the total number of connections, only the total number of unauthorizated ones. This means that 5 people can be in the process of logging on at any given point in time. On a sealed box this is more then enough.

Fortunately by default, FreeBSD's openssh disables rootlogins remote, and empty passwords. I'd also suggest you disable X11Forwarding as well, by changing the X11Forwarding line to read.

X11Forwarding no

If you are running a server, the server should not have XFree installed to begin with. So there's no good reason to have X11Forwarding set to yes in a server configuration. The reasons for turning off X11Forwarding are simple, with X11Forwarding on, a promised server will be able to send processes that can directly attach itself to your X11 session, that means it can log keystrokes, display nasty messages, and capture your display.

Obviously users can still setup X11 sessions if they use simple port forwarding instead, or worse setup unencrypted connections. That however is difficult to stop, but atleast this setting will prevent the more clueless users from doing it. Also this will give the more knowledgable ones the hint you dont want X11 sessions going on between machines.

I also strongly suggest you move away from static passwords completely and use DSA or RSA keys. You can disable password authentication by doing the following. DSA keys are generally considered more secure, but either is fine in my opinion.

PasswordAuthentication no

I will also be writing up a section on how to use DSA or RSA keys. However, at this moment I should simply point out that password authentication is usually not a very secure method regardless of the protocols, cause it can be socially engineered, guessed, stolen from another source or beat out of an employee.

Also regarding SSHD, if your running a server that's going to have alot of accounts present on it, most or many of these accounts will NOT have shell access. I'd recommend doing the following, if nothing else.

AllowGroups shellusers

or

AllowGroups wheel

Or better still, if the number of people with shell access is relatively small you can do the following.

AllowUsers aeonflux

Or whatever your user name is. Allowing only that specific user, or users to access the machine via sshd is usually a very good idea, so you dont accidently end up giving people shell access to your machine, or allow them to setup port forwarding using ssh.

As I'm sure you're aware. If you dont want users to have shell access, you should specify /sbin/nologin as their shell. This can be done using chsh.

chsh -s /sbin/nologin user

Lastly regarding SSHD. Tcpwrappers, sshd in FreeBSD is compiled with tcpwrappers support. While tcpwrappers are a poor replacement for proper packet filtering, I'm of the opinion that a layered security stance is best. Packet filtering can fail, tcpwrappers can fail, however if stacked one ontop of the other, it is less likely to fail.

Open up /etc/hosts.allow

By default you'll need to remove the line "ALL : ALL : allow", as well as some of the other examples. I recommend starting off with a completely blank and fresh file, unless you've already modified your /etc/hosts.allow file. In which case add the following.

sshd : localhost : allow

sshd : friendlycomputer : allow

sshd : all : deny

friendlycomputer being the IP address of machine you wish to login remotely from. I suggest against using hostnames in hosts.allow, since dns can be compromised, spoofed or tampered with at another source. Which ends up making your security dependent on another machines.

That ends our section on SSHD. Lets move on to the client part. Open up /etc/ssh/ssh_config and change it to read as follows.

Host *

ForwardAgent no

ForwardX11 no

Port 22

Protocol 2

Basically make sure Forwarding Agent is turned off, as is Forwarding X11, and make sure it's using Protocol 2. If you want to connect to Protocol 1 daemons, add them in to your ~/.ssh/ssh_config configurations seperately.

As a side note this is the default behavior for the later versions of openssh in FreeBSD. However it is not in other operating systems, nor in other versions of openssh. It's best to get in the habbit of explicitly declaring these things in the configuration files in case the default behavior is changed at a later date. However as it stands it's not necessary to perform this step, although personally I do anyway.

If you'd like your failed ssh logins to show up in the nightly security email as they probably should, you'll need to apply this patch to your /etc/security. By default FreeBSD doesn't audit failed ssh logins. At the moment this patch only checks for failed password logins. I'm going to add failed dsa/rsa key login attempts and illegal users next. Hopefully the final patch will become part of the base install.

We now need to move on to something down the OSI ladder a little, to networking. By default FreeBSD and most operating systems send a RST packet when they receive data close ports. Syn or no they build a new whole packet and send it off, telling an attacker that the port is closed and they should continue scanning the next highest port. Usually we dont want to make portscanning easier, nor do we want to waste valuable cpu cycles in the effect of a dos attack. So we're going to use a little feature in FreeBSD called blackhole. Consult the man page blackhole(4) if you want further information on how this works. If you are using restrict_rst I'd suggest switching over to blackholing as well. It's more effective, and restrict_rst will be removed by release 4.4, as it's already been removed from -stable.

To implement blackholing, do the following. Open up /etc/sysctl.conf and add the following lines.

net.inet.tcp.blackhole=2

net.inet.udp.blackhole=1

This will set the MIB's when you boot up. To activate the changes perform the following command.

# /bin/sh /etc/rc.sysctl

While this isn't a replacement for packet filtering, it is just another additional layer of security. I use it in combination with ipfw to catch anything that falls through the ruleset, or to give me some protection when I've flushed all the rules from some reason. There is another added benefit; if you have to punch holes in your firewall to allow ftp-data, dcc requests or realplayer streaming, you wont be left completely unprotected since any data that slips through the ruleset will be blackholed anyways. It would however be nice if ipfw handled related states a little better.

Lets move on to basic services. You should have a pretty good idea of what services you must run and the ones you dont need. When in doubt disable it, you can always re-enable it later if something/someone needed it. Security needs overrule productivity sometimes, and this is one of them.

First up, open up /etc/rc.conf

Unless you have a good reason to run portmap, such as NFS, NIS and so on, I'd recommend disabling it. People often scan entire network blocks looking for port 111 to see if there are any vulnerable rpc services they can exploit. If you need to run portmap I'd recommend dropping dstport 111 at your border router.

portmap_enable="NO"

Unless your running a mail server, or mail gateway, I'd recommend putting sendmail into queue'ing only mode. If you need to run an actual smtp gateway I'd recommend installing postfix.

sendmail_flags="-q1m"

I'd also suggest you drop icmp redirect, which can be used to dos or hijack sessions. Don't enable it unless you have a specific reason to do so. Even then, it's sometimes best to let packets travel the less optimizal way if it benefits security.

icmp_drop_redirect="YES"

You can also log icmp redirect, however I'd suggest against it because many times Cisco routers will try to send icmp redirects for legit reasons and not as a hack attempt. Depending on your situation you can enable dropped redirect packets to be logged. Personally I do not, as packet filtering takes care of this anyway.

icmp_log_redirect="YES"

For those of you who are curious you can disable that behavior on Cisco routers by doing "no ip send-redirects" on the ethernet interface.

You can also have your machine drop synfin packets. However this does break the TCP specification and there are better ways to do this with IPFW anyway, (more on that later), However if you want to do it, add this to your /etc/rc.conf

tcp_drop_synfin="YES"

Also if you want this behavior to work you'll need to add the following to your kernel configuration.

Next lets talk about crontab. I'd be very careful which users you allow to use crontabs, since it's a very powerful tool to give someone. Also there have been many exploits in cron. It can also be used by an end user to setup bots, waste resources or just annoy people. In the past scriptkiddies have been known to exploit crontab to gain root access on machines. Many times this is possible through a badly designed cgi or server script. The users www, nobody and bind should definitely be denied from creating crontabs.

Create a file /var/cron/allow and put inside a list of the user you want to be able to use cron. For most situations just allowing cron to use crontabs is acceptable. Depending on your individual needs, I suggest just doing the following. In most cases it's better to create an exclusive list, rather then creating a list of users you don't want to create crontabs.

# echo root > /var/cron/allow

# chmod 600 /var/cron/allow

While we're at it, we may want to prevent /etc/crontab from being read globally. Usually this stays unmodified on a system, but there are a few cases when you may want to alter it. Regardless there's no reason to allowing users to read it. So perform the following.

# chmod 600 /etc/crontab

Btw, if you dont use AT (which most people do not), then go ahead and disable it too. Remember the security moto "if you dont use it, lose it". Nature already figured this one out long ago, but us engineers aren't quite as smart. Comment out the /usr/libexec/atrun command in the /etc/crontab file.

# */5 * * * * root /usr/libexec/atrun

inetd and rate limiting

inetd is also on by default. inetd usually controls alot of legacy and therefore insecure services such as telnet, ntalk and finger. There are more modern and superior replacements for inetd. However FreeBSD's inetd is actually one of the better ones around. However, unless you need any of these services, I'd suggest disabling it completely. Check /etc/inetd.conf to see if any of these services are needed by you. FTP for example can also be run in daemon mode, and doesn't require inetd.

To disable inetd, modify the following in your /etc/rc.conf

inetd_enable="NO"

If your going to use FreeBSD's inetd. You should be aware it has built rate limiting ability. For example you can control the rate at which ident requests are processed by doing the following.

The first 10 is the number of maxchild processes we're going to allow. The second value is the max connections per ip per minute. For ident a value of 10/10 is fine. Unless your box is a major smtp gateway there is no reason it should need to process more then 10 ident requests at one time. Even then, dropping ident requests doesn't stop the flow of mail. In fact the only good reason to be running ident these days seems to be irc. If you dont irc, I'd recommend disabling the service entirely.

Rate limiting of this sort will also work for other services as well. Consult the inetd man file if you want to know about how this works.

Time

Make sure your systems clock is set correctly. If your time is incorrect, your log files will basically be worthless. Now your time doesn't need to be super dead on, but within a few minutes is usually sufficient.

By default freebsd comes installed with ntpdate.

# date

Make sure you're in the right timezone.

# ntpdate ntp.nasa.gov

Your date should now be set correctly, using the nasa ntp server, which is from my understanding pretty accurate.

At a later date you can perform the command again and see how much clock drift you have. Usually a few seconds isn't important. You may also want to make it a crontab, in which case ntpdate should be called with the -s flag in other to divert the output to syslog.

It also be noted that your time doesn't need to be exactly dead on to the second. Odds are everyone else's wont be either. So in pratical terms I'd say within 5 minutes is sufficient.

Since we're on the subject of time, dont you find those time marks in syslog to be particularly annoying? Want to remove them?

syslogd_flags="-s -s -m 0"

Added to your /etc/rc.conf, oh and the double -s also has the nice effect of closing the udp port for syslog completely. Unless you're using syslog for logging over the network, I'd suggest setting this.

Securelevels

We could talk about securelevels for an entire article. However let me boil it down to basic terms. Workstations should run at securelevel 0, since they'll probably want to run X11, and servers should probably run in 2 or 1. Depending on how often ymu can reboot the machine to single user mode to make major adjustments. It should also be noted that securelevels can be defeated rather easily by an intelligent cracker, but every additional layer of security helps.

Personally, I run servers at 2, and my laptop and workstations usually run at 0. In /etc/rc.conf modify the following

kern_securelevel_enable="YES"

kern_securelevel="2"

Please consult man init(8), or man securelevel for more information about these. Understand exactly what each level means before implementing it.

You can reboot for these settings to take effect. Or you can just perform.

# sysctl -w kern.securelevel=2

Local Security

Local Security is very important, unfortunately it's something that few open source operating systems really pay proper attention to. If your machine is located at a cmlocation or worse in a data center were mcse's might be wondering about, it usually a good idea to give it some protection.

Now obviously, no form of local security is 100 percent effective if someone wants to wreck your machine and has physical access to it your probably in big trouble (think hammer, bomb, or water). However you can make it rather difficult for them to get at your data or take down your server. Many times accidentically, I've seen mcse's who've hit alt-ctl-del on a freebsd box thinking it was how the login was called.

Lets begin with /etc/ttys, open it up in your favorite editor and find the line.

console none unknown off secure

Change "secure" to "insecure". So the user is asked for the root password when going to single user mode. Be warned this will also make recovering lost root passwords more difficult. But it will prevent someone from gaining root access to your machine locally provided they do not have a boot disk.

This leads us to our next topic for discussion. Modify the BIOS so that the first and/or only boot device is the hard drive. So that even if a cdrom or bootdisk is stuck into the physical machine, Freebsd will be loaded off the hd rather then any hack disks. It also goes without saying that you should password the bios so that a password is required to make changes but not to boot up, because you want your server to be able to reboot without a person standing in front of it. Most modern bios types support this behavior.

Also locking the case, or the whole rack is a good idea to. However this level of physical security is beyond the scope of this document.

Next we need to talk about virtual terminals and virtual terminal buffers. Personally I find this an area of great concern as the virtual terminal buffer does not flush after you logoff. In other words, all of the activity you did locally in front of the machine can be reviewed if someone walks up to your machine and hits scroll lock.

There is however a solution to this on servers, and on workstations that primarily use X. You can disable the virtual console buffer altogether. To do this you'll have to edit your kernel configuration file. If you dont already know how to build your own kernel configuration, please consult the pre existing documentation.

While your editing your kernel configuration you may want to add a few other options relating to syscons. For more information see syscons(4).

SC_DISABLE_DDBKEY # This option disables the debug key.

SC_DISABLE_REBOOT # This option disables the clt-alt-del key.

Finally, if you want login prompt to appear on a blank screen add "clear" to your /etc/csh.logout. It should be noted that this will only clear the screen when you logout, if your using csh.

If you're instead using bash, you'll need to add "clear" to your ~/.bash_logout

XFree86 local security is far mmre tricky. I'd recommend you install the xscreensaver port, and use it to lock your screen when you away from the keyboard. However this does not stop someone from switching virtual terminals and hitting control-c. As far as I know there is no way to prevent someone from switching virtual terminals. You can however, prevent them from gaining control over your account by doing the following.

Within your ~/.profile file create the following alias.

alias startx="startx; exec clear"

What this will do is replace your current shell with startx when startx is called and causing you to be kicked right back to a login prompt when someone uses control-c from the virtual terminal you launched X from. Not a perfect solution, but it does prevent them from zapping out of X and getting access to your shell.

You can also comment the following option in your /etc/X11/XF86Config, which will prevent zapping ctl-alt-backspace but not virtual terminal switching. I'm in the process of writing a "DontSwitch" patch for XFree. This functionality is however already in AcceleratedX.

Also as mentioned before, you should look at the "security/vlock" port. Especially if you have a workstation in a room that can't be locked. I usually run vlock with the -a flag, which locks all the terminals by disabling virtual terminal switching completely.

Option "DontZap"

Packet Filtering

Even though we've already enabled blackholing, it should be noted that it's not a really great alternative to proper packet filtering. So lets talk about FreeBSD's packet filtering suite.

To use ipfw, ymu can either compile support into your kernel or just use the kernel modules. If you setup the rc scripts properly the kernel module will be loaded for you when you boot up.

First lets create our own firewall rules. Create a file /etc/firewall.rules and list inside of it your own rule set. I'd recommend you chmod 600 the file too.

ipfw -q -f flush

ipfw -q add 00100 allow ip from any to any via lo0

ipfw -q add 00220 deny log ip from me to any in

ipfw -q add 00225 deny log tcp from any to any in tcpflags syn,fin

# check the traffic's state, let it in if we sent it, otherwise deny

ipfw -q add 00230 check-state

ipfw -q add 00235 deny tcp from any to any in established

ipfw -q add 00240 allow ip from any to any out keep-state

# allow traffic controlling icmp

ipfw -q add 00300 allow icmp from any to any icmptype 3

ipfw -q add 00301 allow icmp from any to any icmptype 4

ipfw -q add 00302 allow icmp from any to any icmptype 11

# allow dhcp

ipfw -q add 00401 allow udp from 24.128.1.35 67 to any 68

ipfw -q add 00402 allow udp from 24.128.1.34 67 to any 68

# allow ident requests

ipfw -q add 00500 allow tcp from any to any 113 keep-state setup

# log anything that falls through

ipfw -q add 09000 deny log ip from any to any

In this case my dhcp servers are 24.128.1.35 and 24.128.1.34 which are the New England mediaone dhcp servers. Be sure to add your own dhcp servers in, or if your using statically assigned ip addresses remove those lines completely.

Notice how I'm also blocking tcp packets that have the bits syn and fin set. This is because in the wild for the most part packets are not seen with this combination. It is however used by nmap and queso to fingerprint the os, since different os's respond differently to this packet type. So it's best to log it and drop it.

Also notice the rule for dstport 113. Even if your not running ident, it's best to put this rule in here so ident requests aren't logged. It's very annoying to have someone email you threats because their firewall caught an ident request from your network. Ident requests are not hack attempts. Therefore logging them is pointless, and harassing people about them is also pointless.

If your not going to run ident, it's best to change the rule to deny, and remove the keep-state flag. So dynamic rules are not created. Once again, do not bother to log traffic denied by this rule. It's normal network activity and not an attempted network penetration.

Now to active these new firewall rules, perform the following.

# sh /etc/firewall.rules

Now check your connectivity and see if everything is working properly. You may also need to load the module ipfw.ko, if you do however, be sure to set.

# sysctl -w net.inet.ip.fw.verbose=1

This is needed if you want to see the dropped packets in your logs.

Now if you want all this to be done when your machine reboots, you'll need to edit your /etc/rc.conf and add the following.

firewall_enable="YES"

firewall_logging="YES"

firewall_script="/etc/firewall.rules"

Next you'll want to do something useful with the information we're logging. Open up /etc/syslog.conf again and add the following lines.

!ipfw

*.* /var/log/ipfw.log

What this will do is send all the ipfw related data to it's own log file. In this case called ipfw.log. Next of course you'll have to tell syslogd what to do with that log file. Edit /etc/newsyslog.conf and add the following.

/var/log/ipfw.log 600 3 100 * Z

This will do is tell syslog to create a new file /var/log/ipfw.log and give it 600 permissions, and rotate it 3 times after it reaches 100k in size. As well as compressing it when it after it's been rotated for the first time.