One new feature in Solaris 10 that doesn’t get much press is the basic auditing and reporting tool (bart). Bart allows you to generate integrity checks for one or more files on a server. This allows you to compare two groups of file integrity checks (groups of file integrity checks are referred to as manifests in the bart documentation) to see what changed on a server. Bart is super easy to use, and comes with just two options, “create” and “compare.” The “create” option can be used to create a new manifest, and the “compare” option can be used to compare the contents of two manifests. The following example show how to use the “create” option to generate a file integrity check of every file that resides in a global zone’s* root file system:
$ bart create -R / > bart.manifest.08-14-2006.1
$ bart create -R / > bart.manifest.08-14-2006.2
One two manifests are created, the bart “compare” option can be run to compare the manifests:
$ bart compare bart.manifest.08-14-2006.1
bart.manifest.08-14-2006.2
/var/adm/messages:
size control:8866 test:8957
mtime control:44e100a3 test:44e1019e
contents control:b349f015631c87065842009d87a1a456
test:be07b4863f18165fcd154b9f0fce2a64
/var/cron/log:
size control:76152 test:76396
mtime control:44e10070 test:44e1019d
contents control:7cd2f996f0cec248cd5eae4f3e6cce7e
test: 29bf6ecbd171ebe1879e641d5b5739f2
/var/log/pool/poold:
size control:651159 test:652111
mtime control:44e10160 test:44e10232
contents control:9339cb8fac19bb9231e35866cd1a2942 test:89880fbd73332cfc770454fdd034cba1
/var/svc/log/network-ssh:default.log:
size control:226076 test:226181
mtime control:44e10070 test:44e1019d
contents control:5a856f39ede7c7528f9405f573eedd5b
test:778ebe08677923862b03aec5d41e3c51
As you can see from the output above, several logfiles changed between two consecutive runs. While not a complete file integrity solution, bart is a super useful utility, and should be used after each system installation and patch application.
The bart manual page states that you shouldn’t run bart on the root file system in a non-global zone.
I attended Jay Beale’s Discovering OS X weaknesses and fixing them with the new Bastille Linux port at Defcon last week. Jay did a great job presenting, and pointed out several HUGE flaws that are present with the default OS X “stealth” firewall rule set. The first major problem Jay pointed out was the fact that all UDP datagrams with source port 67 or 5353 are allowed in (this allows you to talk to ntpd and cups, which have a rocky security history). The second major flaw is the fact that the default configuration blocks ICMP type code 8 (ICMP echo requests), but allows all other ICMP traffic in. And finally, OS X defaults to an allow any rule, which allows cruft like bonjour and the service locator to pollute your network with the version of OS X you are running, and the hardware architecture you are running on (this is a shell coders dream!). I take security rather seriously, so I sat down the night I got home and read the ipfw manual page, and created the following firewall rule set to deny all traffic by default, and allow a few trusted services out:
$ cat /etc/rc.firewall
#!/bin/sh
# Variables to simplify maintenance (these are comma delimited)
DNS_SERVERS="10.1.1.1"
# Enable firewall logging
/usr/sbin/sysctl -w net.inet.ip.fw.verbose=1
# Flush existing rules
/sbin/ipfw -f flush
# If the rule was added to the dynamic rule table, let it in
/sbin/ipfw add check-state
# Allow traffic to flow on the loopback interface
/sbin/ipfw add allow all from any to any via lo0
# Allow established connections
/sbin/ipfw add allow tcp from any to any established
# Allow SSH connections
/sbin/ipfw add allow tcp from me to any 22 keep-state
# Allow non-secure web traffic
/sbin/ipfw add allow tcp from me to any 80 keep-state
# Allow secure web traffic
/sbin/ipfw add allow tcp from me to any 443 keep-state
# Allow secure LDAP traffic
/sbin/ipfw add allow tcp from me to any 636 keep-state
# Allow IMAPS
/sbin/ipfw add allow tcp from me to any 993 keep-state
# Allow me to get to my DNS servers
/sbin/ipfw add allow udp from me to ${DNS_SERVERS} 53 keep-state
# Optionally allow ICMP traffic out
# /sbin/ipfw add allow icmp from me to any out keep-state
# Deny everything else
ipfw add deny log ip from any to any
To enable the policy at startup, you need to place the rules listed above in a file, and make the file executable. This blog entry assumes the rules were placed in the file /etc/rc.firewall. Next, you will need to create an entry in the system startup folder. Each startup item contains a script to start and stop the service, and a property file to control when and how the service starts. To enable the firewall policy listed above, we can create a file called /Library/StartupItems/Firewall/Firewall with start, stop and restart actions:
$ cat /Library/StartupItems/Firewall/Firewall
#!/bin/sh
##
# Firewall
##
. /etc/rc.common
case "$1" in
start)
ConsoleMessage "Starting Firewall"
# Activate the firewall rules
/etc/rc.firewall > /dev/null
;;
stop)
echo "Stopping Firewall..."
/sbin/ipfw -f flush
;;
restart)
ConsoleMessage "Retarting Firewall"
# Activate the firewall rules
/etc/rc.firewall > /dev/null
;;
esac
exit 0
In addition to the script listed above, you will also need to create a properties file to tell OS X when the service should start, and any dependencies that need to be online before the service is started. The properties file should be placed in the same directory as the startup script, and named StartupParameters.plist. The following property file can be used along with the Firewall startup script listed above:
$ cat /Library/StartupItems/Firewall/StartupParameters.plist
{
Description = "Firewall";
Provides = ("Firewall");
Requires = ("NetworkExtensions","Resolver");
OrderPreference = "Late";
Messages =
{
start = "Starting firewall";
stop = "Stopping firewall";
};
}
Once all three files are in place, you can reboot the machine, and run ‘ipfw show’ as the root user to make sure the policy is installed. Daniel Cote has a great write up on building robust OS X firewall (ipfw) rulesets (I didn’t need some of the bells and whistles provided by Daniel’s firewall.sh.current script, so I reduced the rules to exactly what I need to filter inbound and outbound traffic). The Firewall and StartupParameters.plist files were taken from the firewall tarball on Daniel’s website, and I would like to thank him for putting together such an awesome website!
While performing some basic traffic analysis on my home wireless network, I noticed the folllowing broadcast traffic:
$ tcpdump -i en1 broadcast or multicast
15:51:25.761928 IP (tos 0x0, ttl 64, id 28912, offset 0, flags [none],
proto: UDP (17), length: 180) 192.168.1.10.52330 >
255.255.255.255.2222: UDP, length 152
15:52:25.765492 IP (tos 0x0, ttl 64, id 28951, offset 0, flags [none],
proto: UDP (17), length: 180) 192.168.1.10.52331 >
255.255.255.255.2222: UDP, length 152
15:53:25.769116 IP (tos 0x0, ttl 64, id 28989, offset 0, flags [none],
proto: UDP (17), length: 180) 192.168.1.10.52332 >
255.255.255.255.2222: UDP, length 152
Gak! I disabled rendezous on my laptop to avoid polluting the ether, and the applications that were running shouldn’t be broadcasting messages! I was curious to see what was causing this, so I went into discovery mode. After reviewing ktrace, netstat and lsof data, I realized that the traffic was coming from Microsoft Word. It turns out that Microsoft Word sends broadcast messages to ensure that a license is only being used on a single node. This is supposed to help combat piracy, but I didn’t agree to this when I signed the EULA. This was extremely annoying, and what made it worse is the fact that Microsoft Word also listens on a TCP port:
$ lsof -i | grep Microsoft
Microsoft 1208 matty 19u IPv4 0x0283a590 0t0 TCP *:3797 (LISTEN)
Last week Microsoft released several critical Office patches for the Windows paltform (I am not sure if these apply to OS X yet, so I don’t want Microsoft office application blindly sending or accepting data). My laptop now uses a selectively allow and deny everything else firewall policy, which stops this cruft from meandering throughout my home network. If you don’t feel like mucking with the default firewall policy, you can add an ipfw rule similar to the following to block this traffic:
$ /sbin/ipfw add deny udp from any to any 2222 out
I reckon it’s time to switch to Pages for word processing.
I wrote about pca a few weeks back, and absolutely love the capabilities it brings to the table. To keep my servers up date with the latest security patches, I added the following cron job to extract security patches from the pca output, and E-mail them to my account:
0 0 * * * pca -l | awk '$5 ~ /S/ { print $0}' | mailx -s "Security updates for $HOSTNAME" root
This works pretty well, and I now get E-mailed when security patches are available.
The postfix mail delivery system allows one or more restrictions to be placed on incoming messages. These restrictions allow you to block messages when clients don’t use the SMTP handshake as outlined in RFC 821 during delivery, if the name supplied in the HELO is not fully qualified or fails to resolve, or if the connecting host resides on one or more blacklists. Several restrictions come enabled by default, but others need to be manually enabled by adding additional directives to the smtpd_helo_restrictions, smtpd_sender_restrictions and smtpd_recipient_restrictions variables. Since new restrictions can have unexpected results (e.g., lost E-mail), it is beneficial to test these rules prior to enforcing them.
The soft_bounce directive is one way to test out new rules. When soft_bounce is set in the main.cf, a message that would be blocked by a restriction is rejected with a soft reject error code (typically something in the 4XX range). The soft reject will force the sending host to queue the message, and attempt redelivery at a later date. Each time a soft bounce occurs, postfix will log a message to the logging facility. Since the server that sent the message will attempt to redeliver the message at a later date, you can tweak the configuration prior to the next delivery attempt if you want to accept mail from the host that matched the restriction. This method does have one major drawback. Numerous MTAs on the Internet use low TTLs on messages in their mail queues, so using soft bounces can result in messages getting returned to the sender if the restriction isn’t adjusted in a timely manner.
An alternative method to soft bounces is the warn_if_reject qualifier. Instead of soft bouncing the message if the sender matches a restriction, the warn_if_reject qualifier will cause postfix to deliver the message, and log a warning when a message matches a restriction. This ensures that mail is delivered if the restriction has an unknown side effect, and allows the mail admin to test restrictions in a non-intrusive way. Warn_if_reject can be applied to all of the postfix restrictions ( I have yet to find a restriction that warn_if_reject doesn’t apply to, but there may be some), and is set by prepending the string “warn_if_reject” to the restriction:
smtpd_helo_restrictions = permit_mynetworks,
reject_non_fqdn_hostname,
warn_if_reject reject_invalid_hostname,
warn_if_reject reject_unknown_hostname
To get a daily report with messages that matched the restriction, you can use the awesome pflogsum Perl script. Using warn_if_reject has saved me a fair amount of grief, and is a great way to make sure a restriction does what you want it to.