Senin, 26 November 2007

Controls Are Not the Solution to Our Problem

If you recognize the inspiration for this post title and graphic, you'll understand my ultimate goal. If not, let me start by saying this post is an expansion of ideas presented in a previous post with the succinct and catchy title Control-Compliant vs Field-Assessed Security.

In brief, too many organizations, regulators, and government agencies waste precious time and resources devising and auditing "controls," regardless of the effect these controls have or do not have on security. They are far too input-centric; they should become more output-aware. They obsess over recording conditions they believe may be helpful while remaining ignorant of the "score of the game." They practice management by belief and disregard management by fact.

Let me provide a few examples from one of the canonical texts used by the control-compliant crowd: NIST Special Publication 800-53: Recommended Security Controls for Federal Information Systems (.pdf). The following is an example of a control, taken from page 140.

SI-3 MALICIOUS CODE PROTECTION


The information system implements malicious code protection.

Control: Supplemental Guidance: The organization employs malicious code protection mechanisms at critical information system entry and exit points (e.g., firewalls, electronic mail servers, web servers, proxy servers, remote-access servers) and at workstations, servers, or mobile computing devices on the network. The organization uses the malicious code protection mechanisms to detect and eradicate malicious code (e.g., viruses, worms, Trojan horses, spyware) transported: (i) by electronic mail, electronic mail attachments, Internet accesses, removable media (e.g., USB devices, diskettes or compact disks), or other common means; or (ii) by exploiting information system vulnerabilities. The organization updates malicious code protection mechanisms (including the latest virus definitions) whenever new releases are available in accordance with organizational configuration management policy and procedures. The organization considers using malicious code protection software products from multiple vendors (e.g., using one vendor for boundary devices and servers and another vendor for workstations). The organization also considers the receipt of false positives during malicious code detection and eradication and the resulting potential impact on the availability of the information system. NIST Special Publication 800-83 provides guidance on implementing malicious code protection.

Control Enhancements:
(1) The organization centrally manages malicious code protection mechanisms.
(2) The information system automatically updates malicious code protection mechanisms.


At first read one might reasonably respond by saying "What's wrong with that? This control advocates implementing anti-virus and related anti-malware software." Think more clearly about this issue and several problems appear.

  • Adding anti-virus products can introduce additional vulnerabilities to systems which might not have exposed themselves without running anti-virus. Consider my post Example of Security Product Introducing Vulnerabilities if you need examples. In short, add anti-virus, be compromised.

  • Achieving compliance may cost more than potential damage. How many times have you heard a Unix administrator complain that he/she has to purchase an anti-virus product for his/her Unix server simply to be compliant with a control like this? The potential for a Unix server (not Mac OS X) to be damaged by a user opening an email through a client while logged on to the server (a very popular exploitation vector on a Windows XP box) is practically nil.

  • Does this actually work? This is the question that no one asks. Does it really matter if your system is running anti-virus software? Did you know that intruders (especially high-end ones most likely to selectively, steathily target the very .gov and .mil systems required to be compliant with this control) test their malware against a battery of anti-virus products to ensure their code wins? Are weekly updates superior to daily updates? Daily to hourly?


The purpose of this post is to tentatively propose an alternative approach. I called this "field-assessed" in contrast to "control-compliant." Some people prefer the term "results-based." Whatever you call it, the idea is to direct attention away from inputs and devote more energy to outputs. As far as mandating inputs (like every device must run anti-virus), I say that is a waste of time and resources.

I recommend taking measurements to determine your enterprise "score of the game," and use that information to decide what you need to do differently. I'm not suggesting abandoning efforts to prevent intrusions (i.e., "inputs.") Rather, don't think your security responsibilities end when the bottle is broken against the bow of the ship and it slides into the sea. You've got to keep watching to see if it sinks, if pirates attack, how the lifeboats handle rough seas, and so forth.

These are a few ideas.

  1. Standard client build client-side survival test. Create multiple sacrificial systems with your standard build. Deploy a client-side testing solution on them, like a honeyclient. (See The Sting for a recent story.) Vary your defensive posture. Measure how long it takes for your standard build to be compromised by in-the-wild Web sites, spam, and other communications with the outside world.

  2. Standard client build server-side survival test. Create multiple sacrificial systems with your standard build. Deploy them as a honeynet. Vary your defensive posture. Measure how long it takes for your standard build to be compromised by malicious external traffic from the outside world -- or better yet -- from your internal network.

  3. Standard client build client-side penetration test. Create multiple sacrificial systems with your standard build. Conduct my recommendation penetration testing activities and time the result.

  4. Standard client build server-side penetration test. Repeat number 3 with a server-side flavor.

  5. Standard server build server-side penetration test. Repeat number 3 against your server build with a server-side flavor. I hope you don't have users operating servers as if they were clients (i.e., browsing the Web, reading email, and so forth.) If you do, repeat this step and do a client-side pen test too.

  6. Deploy low-interactive honeynets and sinkhole routers in your internal network. These low-interaction systems provide a means to get some indications of what might be happening inside your network. If you think deploying these on the external network might reveal indications of targeted attacks, try that. (I doubt it will be that useful due to the overall attack noise, but who knows?)

  7. Conduct automated, sampled client host integrity assessments. Select a statistically valid subset of your clients and check them using multiple automated tools (malware/rootkit/etc. checkers) for indications of compromise.

  8. Conduct automated, sampled server host integrity assessments. Self-explanatory.

  9. Conduct manual, sampled client host integrity assessments. These are deep-dives of individual systems. You can think of it as an incident response where you have not had indication of an incident yet. Remote IR tools can be helpful here. If you are really hard-core and you have the time, resources, and cooperation, do offline analysis of the hard drive.

  10. Conduct manual, sampled server host integrity assessments. Self-explanatory.

  11. Conduct automated, sampled network host activity assessments. I questioned adding this step here, since you should probably always be doing this. Sometimes it can be difficult to find the time to review the results, however automated the data collection. The idea is to let your NSM system see if any of the traffic it sees is out of the ordinary based on algorithms you provide.

  12. Conduct manual, sampled network host activity assessments. This method is more likely to produce results. Here a skilled analyst performs deep individual analysis of traffic on a sample of machines (client and server, separately) to see if any indications of compromise appear.


In all of these cases, trend your measurements over time to see if you see improvements when you alter an input. I know some of you might complain that you can't expect to have consistent output when the threat landscape is constantly changing. I really don't care, and neither does your CEO or manager!

I offer two recommendations:

  • Remember Andy Jaquith's criteria for good metrics, simplified here.


    1. Measure consistently.

    2. Make them cheap to measure. (Sorry Andy, my manual tests violate this!)

    3. Use compound metrics.

    4. Be actionable.


  • Don't slip into thinking of inputs. Don't measure how many hosts are running anti-virus. We want to measure outputs. We are not proposing new controls.


Controls are not the solution to our problem. Controls are the problem. They divert too much time, resources, and attention from endeavors which do make a difference. If the indications I am receiving from readers and friends are true, the ideas in this post are gaining traction. Do you have other ideas?

Minggu, 25 November 2007

Old School Oracle Auditing

I was again reading for hacking articles and one of the article "Simple Oracle Auditing" caught my attention. Well, its an old article but its still fun to read and learn from the gurus. Check it out guys: http://www.securityfocus.com/infocus/1689

The Hacka Man

Jumat, 23 November 2007

MPAA University Toolkit Phone Home

This is a follow-up to my story Examining the MPAA University Toolkit.

After reading the hysteria posted on the Slashdot story MPAA College Toolkit Raises Privacy, Security Concerns, I thought I would take a look at traffic leaving the box. Aside from traffic generated by the auto-start of Firefox, the only interesting event was the following. I captured it with my gateway Sguil sensor.

Sensor Name: hacom
Timestamp: 2007-11-23 21:27:04
Connection ID: .hacom_5136150487897024842
Src IP: 69.255.105.234 (c-69-255-105-234.hsd1.va.comcast.net)
Dst IP: 66.252.137.155 (Unknown)
Src Port: 39532
Dst Port: 80
OS Fingerprint: 69.255.105.234:39532 - UNKNOWN
[S4:61:1:60:M1460,S,T,N,W4:.:?:?] (up: 3 hrs)
OS Fingerprint: -> 66.252.137.155:80 (link: ethernet/modem)

SRC: GET /version.txt HTTP/1.1
SRC: Accept-Encoding: identity
SRC: Host: universitytoolkit.com
SRC: Connection: close
SRC: User-Agent: Python-urllib/2.5
SRC:
SRC:
DST: HTTP/1.1 200 OK
DST: Date: Fri, 23 Nov 2007 21:27:31 GMT
DST: Server: Apache/2.0.52 (Red Hat)
DST: Last-Modified: Fri, 12 Oct 2007 14:14:45 GMT
DST: ETag: "4f4002-7-57333f40"
DST: Accept-Ranges: bytes
DST: Content-Length: 7
DST: Connection: close
DST: Content-Type: text/plain; charset=UTF-8
DST:
DST: 1.2-RC3

That's it.

Examining the MPAA University Toolkit

I learned about the MPAA University Toolkit at Brian Krebs' always-excellent SecurityFix blog. If you want to know more about the user experience, please check out that post. Here I take a look at the monitoring software, focusing on Snort, operating on this application.

I downloaded the 534 MB peerwatch-1.2-RC5.iso and started it in a VMware Server session. I used ctrl-c and then 'sudo bash' to exit from the initial script presented within X, set a root password, then used 'apt-get ssh install' to install OpenSSH and thus enable root access. From this point forward I accessed the system using OpenSSH remotely to facilitate copying information into this blog post.

First, this looks like Ubuntu (Xubuntu, if you really care) Feisty Fawn, or 7.04.

root@ubuntu:~# uname -a
Linux ubuntu 2.6.20-15-generic #2 SMP Sun Apr 15 07:36:31 UTC 2007
i686 GNU/Linux

I was most interested in learning about Snort on this toolkit. I saw this version installed.

root@ubuntu:~# snort -V

,,_ -*> Snort! <*-
o" )~ Version 2.3.3 (Build 14)
'''' By Martin Roesch & The Snort Team: http://www.snort.org/team.html
(C) Copyright 1998-2004 Sourcefire Inc., et al.

Wow, that's old. It's probably patched base on the changelog. This is Snort installed via Debian/Ubuntu package:

root@ubuntu:~# dpkg --list | grep snort
rc snort 2.3.3-9
Flexible Network Intrusion Detection System
ii snort-common 2.3.3-9
Flexible Network Intrusion Detection System
ii snort-mysql 2.3.3-9
Flexible Network Intrusion Detection System
ii snort-rules-default 2.3.3-9
Flexible Network Intrusion Detection System

Let's see what the snort.conf looks like.

root@ubuntu:/etc/snort# cat snort.conf
var HOME_NET any
var EXTERNAL_NET !$HOME_NET
var DNS_SERVERS $HOME_NET
var SMTP_SERVERS $HOME_NET
var HTTP_SERVERS $HOME_NET
var SQL_SERVERS $HOME_NET
var TELNET_SERVERS $HOME_NET
var SNMP_SERVERS $HOME_NET

var HTTP_PORTS 80

var RULE_PATH /etc/snort/rules

preprocessor flow: stats_interval 0 hash 2
preprocessor frag2
preprocessor stream4: disable_evasion_alerts detect_scans
preprocessor stream4_reassemble

# preprocessor perfmonitor: time 300 file /var/snort/snort.stats pktcnt 10000

# (#DBSTART#)
output database: log, mysql, user=snort password=snort dbname=snort host=localhost
# (#DBEND#)

include classification.config
include reference.config

config flowbits_size: 256

include $RULE_PATH/bleeding-p2p.rules
include $RULE_PATH/local-ftp.rules
include $RULE_PATH/local-http.rules
include $RULE_PATH/local-smb.rules
include $RULE_PATH/p2p.rules

include threshold.conf

Excellent, another Snort installation where Snort is logging directly to a MySQL database. That must be the default provided by Debian/Ubuntu. Ouch. Thresholding and suppression are also enabled but the entire contents are commented out in the threshold.conf file.

Let's get a look at those rules.

bleeding-p2p.rules looks like an old copy of the bleeding-p2p.rules, perhaps from mid-year? I think there are 38 rules.

p2p.rules is a really old rule set:

# $Id: p2p.rules,v 1.17.2.1 2004/10/13 20:25:57 bmc Exp $

You may recognize these and the other Snort distributed-rules as being those that accompanied Snort 2.3.3, which pre-dates the new license for Snort rules.

local-ftp.rules is the first rule set written by whomever assembled this toolkit.

# cat local-ftp.rules
# 1 000 500 - 1 000 699

# active
alert tcp any 20 -> any any (msg: "FTP Download - MPEG Movie File - B2"; \
content: "|00 00 01 B2|"; depth: 6; rawbytes; \
sid: 1000501; rev: 1; \
)

alert tcp any 20 -> any any (msg: "FTP Download - MPEG Movie File - B3"; \
content: "|00 00 01 B3|"; depth: 6; rawbytes; \
sid: 1000502; rev: 1; \
)

alert tcp any 20 -> any any (msg: "FTP Download - MPEG Movie File - BA"; \
content: "|00 00 01 BA|"; depth: 6; rawbytes; \
sid: 1000503; rev: 1; \
)

alert tcp any 20 -> any any (msg: "FTP Download - MPEG Movie File - BB"; \
content: "|00 00 01 BB|"; depth: 6; rawbytes; \
sid: 1000504; rev: 1; \
)

alert tcp any 20 -> any any (msg: "FTP Download - MPEG-4 Video File"; \
content: "|00 00 00 18 66 74 79 70 6D 70 34|"; depth: 15; rawbytes; \
sid: 1000505; rev: 1; \
)

alert tcp any 20 -> any any (msg: "FTP Download - Quicktime Movie File - MOOV"; \
content: "|6D 6F 6F 76|"; depth: 10; rawbytes; \
sid: 1000506; rev: 1; \
)

alert tcp any 20 -> any any (msg: "FTP Download - Quicktime Movie File - MDAT"; \
content: "|6D 64 61 74|"; depth: 10; rawbytes; \
sid: 1000507; rev: 1; \
)

alert tcp any 20 -> any any (msg: "FTP Download - Audio Video Interleave (AVI) File - AVI"; \
content: "|41 56 49 20|"; depth: 6; rawbytes; \
sid: 1000508; rev: 1; \
)

alert tcp any 20 -> any any (msg: "FTP Download - Audio Video Interleave (AVI) File - RIFF"; \
content: "|52 49 46 46|"; depth: 6; rawbytes; \
sid: 1000509; rev: 1; \
)

alert tcp any 20 -> any any (msg: "FTP Download - Real Media File"; \
content: "|2E 52 4D 46|"; depth: 6; rawbytes; \
sid: 1000510; rev: 1; \
)

alert tcp any 20 -> any any (msg: "FTP Download - Windows Media File"; \
content: "|30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C|"; depth: 20; rawbytes; \
sid: 1000511; rev: 1; \
)

# passive
alert tcp any 1024: -> any 1024: (msg: "FTP PASV Download - MPEG Movie File - B2"; \
content: "|00 00 01 B2|"; depth: 6; rawbytes; \
sid: 1000512; rev: 1; \
)

alert tcp any 1024: -> any 1024: (msg: "FTP PASV Download - MPEG Movie File - B3"; \
content: "|00 00 01 B3|"; depth: 6; rawbytes; \
sid: 1000513; rev: 1; \
)

alert tcp any 1024: -> any 1024: (msg: "FTP PASV Download - MPEG Movie File - BA"; \
content: "|00 00 01 BA|"; depth: 6; rawbytes; \
sid: 1000514; rev: 1; \
)

alert tcp any 1024: -> any 1024: (msg: "FTP PASV Download - MPEG Movie File - BB"; \
content: "|00 00 01 BB|"; depth: 6; rawbytes; \
sid: 1000515; rev: 1; \
)

alert tcp any 1024: -> any 1024: (msg: "FTP PASV Download - MPEG-4 Video File"; \
content: "|00 00 00 18 66 74 79 70 6D 70 34|"; depth: 15; rawbytes; \
sid: 1000516; rev: 1; \
)

alert tcp any 1024: -> any 1024: (msg: "FTP PASV Download - Quicktime Movie File - MOOV"; \
content: "|6D 6F 6F 76|"; depth: 10; rawbytes; \
sid: 1000517; rev: 1; \
)

alert tcp any 1024: -> any 1024: (msg: "FTP PASV Download - Quicktime Movie File - MDAT"; \
content: "|6D 64 61 74|"; depth: 10; rawbytes; \
sid: 1000518; rev: 1; \
)

alert tcp any 1024: -> any 1024: (msg: "FTP PASV Download - Audio Video Interleave (AVI) File - AVI"; \
content: "|41 56 49 20|"; depth: 6; rawbytes; \
sid: 1000519; rev: 1; \
)

alert tcp any 1024: -> any 1024: (msg: "FTP PASV Download - Audio Video Interleave (AVI) File - RIFF"; \
content: "|52 49 46 46|"; depth: 6; rawbytes; \
sid: 1000520; rev: 1; \
)

alert tcp any 1024: -> any 1024: (msg: "FTP PASV Download - Real Media File"; \
content: "|2E 52 4D 46|"; depth: 6; rawbytes; \
sid: 1000521; rev: 1; \
)

alert tcp any 1024: -> any 1024: (msg: "FTP PASV Download - Windows Media File"; \
content: "|30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C|"; depth: 20; rawbytes; \
sid: 1000522; rev: 1; \
)

Anyone who has written Snort rules is probably going to question the false positive rate on this rule set, especially the "tcp any 1024: -> any 1024:" group. These are straight content matches, and the smaller strings like "|2E 52 4D 46|" are probably going to fire quite a bit on unintended traffic.

Here is local-http.rules.

root@ubuntu:/etc/snort/rules# cat local-http.rules
# 1 000 100 - 1 000 299

alert tcp any 80 -> any any (msg: "HTTP Download > 100M - MPEG Movie File - B2"; \
flow: established,from_server; \
content: "HTTP"; depth: 5; nocase; \
content: "200"; within: 8; \
content: "Content-Length\: "; within: 300; nocase; \
pcre: "/^[0-9]{9,}\r\n/R"; \
content: "|0d 0a 0d 0a|"; within: 100; \
content: "|00 00 01 B2|"; within: 6; \
sid: 1000101; rev: 1; \
)

alert tcp any 80 -> any any (msg: "HTTP Download > 100M - MPEG Movie File - B3"; \
flow: established,from_server; \
content: "HTTP"; depth: 5; nocase; \
content: "200"; within: 8; \
content: "Content-Length\: "; within: 300; nocase; \
pcre: "/^[0-9]{9,}\r\n/R"; \
content: "|0d 0a 0d 0a|"; within: 100; \
content: "|00 00 01 B3|"; within: 6; \
sid: 1000102; rev: 1; \
)

alert tcp any 80 -> any any (msg: "HTTP Download > 100M - MPEG Movie File - BA"; \
flow: established,from_server; \
content: "HTTP"; depth: 5; nocase; \
content: "200"; within: 8; \
content: "Content-Length\: "; within: 300; nocase; \
pcre: "/^[0-9]{9,}\r\n/R"; \
content: "|0d 0a 0d 0a|"; within: 100; \
content: "|00 00 01 BA|"; within: 6; \
sid: 1000103; rev: 1; \
)

alert tcp any 80 -> any any (msg: "HTTP Download > 100M - MPEG Movie File - BB"; \
flow: established,from_server; \
content: "HTTP"; depth: 5; nocase; \
content: "200"; within: 8; \
content: "Content-Length\: "; within: 300; nocase; \
pcre: "/^[0-9]{9,}\r\n/R"; \
content: "|0d 0a 0d 0a|"; within: 100; \
content: "|00 00 01 BB|"; within: 6; \
sid: 1000104; rev: 1; \
)

alert tcp any 80 -> any any (msg: "HTTP Download > 100M - MPEG-4 Video File"; \
flow: established,from_server; \
content: "HTTP"; depth: 5; nocase; \
content: "200"; within: 8; \
content: "Content-Length\: "; within: 300; nocase; \
pcre: "/^[0-9]{9,}\r\n/R"; \
content: "|0d 0a 0d 0a|"; within: 100; \
content: "|00 00 00 18 66 74 79 70 6D 70 34|"; within: 15; \
sid: 1000105; rev: 1; \
)

alert tcp any 80 -> any any (msg: "HTTP Download > 100M - Quicktime Movie File - MOOV"; \
flow: established,from_server; \
content: "HTTP"; depth: 5; nocase; \
content: "200"; within: 8; \
content: "Content-Length\: "; within: 300; nocase; \
pcre: "/^[0-9]{9,}\r\n/R"; \
content: "|0d 0a 0d 0a|"; within: 100; \
content: "|6D 6F 6F 76|"; within: 10; \
sid: 1000106; rev: 1; \
)
alert tcp any 80 -> any any (msg: "HTTP Download > 100M - Quicktime Movie File - MDAT"; \
flow: established,from_server; \
content: "HTTP"; depth: 5; nocase; \
content: "200"; within: 8; \
content: "Content-Length\: "; within: 300; nocase; \
pcre: "/^[0-9]{9,}\r\n/R"; \
content: "|0d 0a 0d 0a|"; within: 100; \
content: "|6D 64 61 74|"; within: 10; \
sid: 1000107; rev: 1; \
)

alert tcp any 80 -> any any (msg: "HTTP Download > 100M - Audio Video Interleave (AVI) File - AVI"; \
flow: established,from_server; \
content: "HTTP"; depth: 5; nocase; \
content: "200"; within: 8; \
content: "Content-Length\: "; within: 300; nocase; \
pcre: "/^[0-9]{9,}\r\n/R"; \
content: "|0d 0a 0d 0a|"; within: 100; \
content: "|41 56 49 20|"; within: 6; \
sid: 1000108; rev: 1; \
)

alert tcp any 80 -> any any (msg: "HTTP Download > 100M - Audio Video Interleave (AVI) File - RIFF"; \
flow: established,from_server; \
content: "HTTP"; depth: 5; nocase; \
content: "200"; within: 8; \
content: "Content-Length\: "; within: 300; nocase; \
pcre: "/^[0-9]{9,}\r\n/R"; \
content: "|0d 0a 0d 0a|"; within: 100; \
content: "|52 49 46 46|"; within: 6; \
sid: 1000109; rev: 1; \
)

alert tcp any 80 -> any any (msg: "HTTP Download > 100M - Real Media File"; \
flow: established,from_server; \
content: "HTTP"; depth: 5; nocase; \
content: "200"; within: 8; \
content: "Content-Length\: "; within: 300; nocase; \
pcre: "/^[0-9]{9,}\r\n/R"; \
content: "|0d 0a 0d 0a|"; within: 100; \
content: "|2E 52 4D 46|"; within: 6; \
sid: 1000110; rev: 1; \
)

alert tcp any 80 -> any any (msg: "HTTP Download > 100M - Windows Media File"; \
flow: established,from_server; \
content: "HTTP"; depth: 5; nocase; \
content: "200"; within: 8; \
content: "Content-Length\: "; within: 300; nocase; \
pcre: "/^[0-9]{9,}\r\n/R"; \
content: "|0d 0a 0d 0a|"; within: 100; \
content: "|30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C|"; within: 20; \
sid: 1000111; rev: 1; \
)

That's 11 rules. There are 22 more. The middle 11 have port 80 replaced by 3128. The final 11 have port 8080. What does that tell you? It means that you can avoid being detected by these rules if the remote Web server runs on a port other than 80, 3128, or 8080. Note also that the original snort.conf doesn't enable the http_inspect or http_inspect_server preprocessors. These rules are more raw content matches, although their specificity will reduce the number of times they fire. They also introduce more evasion options.

Finally, let's check out local-smb.rules.

root@ubuntu:/etc/snort/rules# cat local-smb.rules
# 1 000 300 - 1 000 499

alert tcp any 445 -> any any (msg: "SMB-445 Download > 100M - MPEG Movie File - B2"; \
flow: established,from_server; \
content: "SMB|2E|"; offset: 5; within: 4; nocase; \
content: "|00 00 01 B2|"; distance: 54; within: 4; \
sid: 1000301; rev: 1; \
)

alert tcp any 445 -> any any (msg: "SMB-445 Download > 100M - MPEG Movie File - B3"; \
flow: established,from_server; \
content: "SMB|2E|"; offset: 5; within: 4; nocase; \
content: "|00 00 01 B3|"; distance: 54; within: 4; \
sid: 1000302; rev: 1; \
)

alert tcp any 445 -> any any (msg: "SMB-445 Download > 100M - MPEG Movie File - BA"; \
flow: established,from_server; \
content: "SMB|2E|"; offset: 5; within: 4; nocase; \
content: "|00 00 01 BA|"; distance: 54; within: 4; \
sid: 1000303; rev: 1; \
)

alert tcp any 445 -> any any (msg: "SMB-445 Download > 100M - MPEG Movie File - BB"; \
flow: established,from_server; \
content: "SMB|2E|"; offset: 5; within: 4; nocase; \
content: "|00 00 01 BB|"; distance: 54; within: 4; \
sid: 1000304; rev: 1; \
)

alert tcp any 445 -> any any (msg: "SMB-445 Download > 100M - MPEG-4 Video File"; \
flow: established,from_server; \
content: "SMB|2E|"; offset: 5; within: 4; nocase; \
content: "|00 00 00 18 66 74 79 70 6D 70 34|"; distance: 54; within: 15; \
sid: 1000305; rev: 1; \
)

alert tcp any 445 -> any any (msg: "SMB-445 Download > 100M - Quicktime Movie File - MOOV"; \
flow: established,from_server; \
content: "SMB|2E|"; offset: 5; within: 4; nocase; \
content: "MOOV"; distance: 54; within: 8; nocase; \
sid: 1000306; rev: 1; \
)

alert tcp any 445 -> any any (msg: "SMB-445 Download > 100M - Quicktime Movie File - MDAT"; \
flow: established,from_server; \
content: "SMB|2E|"; offset: 5; within: 4; nocase; \
content: "MDAT"; distance: 54; within: 4; nocase; \
sid: 1000307; rev: 1; \
)

alert tcp any 445 -> any any (msg: "SMB-445 Download > 100M - Audio Video Interleave (AVI) File - AVI"; \
flow: established,from_server; \
content: "SMB|2E|"; offset: 5; within: 4; nocase; \
content: "AVI_"; distance: 54; within: 4; nocase; \
sid: 1000308; rev: 1; \
)

alert tcp any 445 -> any any (msg: "SMB-445 Download > 100M - Audio Video Interleave (AVI) File - RIFF"; \
flow: established,from_server; \
content: "SMB|2E|"; offset: 5; within: 4; nocase; \
content: "RIFF"; distance: 54; within: 4; nocase; \
sid: 1000309; rev: 1; \
)

alert tcp any 445 -> any any (msg: "SMB-445 Download > 100M - Real Media File"; \
flow: established,from_server; \
content: "SMB|2E|"; offset: 5; within: 4; nocase; \
content: "|2E 52 4D 46|"; distance: 54; within: 4; \
sid: 1000310; rev: 1; \
)

alert tcp any 445 -> any any (msg: "SMB-445 Download > 100M - Windows Media File"; \
flow: established,from_server; \
content: "SMB|2E|"; offset: 5; within: 4; nocase; \
content: "|30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C|"; distance: 54; within: 16; \
sid: 1000311; rev: 1; \
)

Notice all the port 445 instances? You can evade these if your SMB session uses port 139 TCP.

I thought it might be fun to test these rules. I decided to download a 108 MB .avi file to the toolkit host itself and see if would be observed.

file robert-morris.avi
robert-morris.avi: RIFF (little-endian) data, AVI, 640 x 480, 30.00 fps,
video: Motion JPEG, audio: uncompressed PCM (mono, 11024 Hz)

Hmm, no alerts. I have Sguil running on my gateway. Let's see what the start of a transcript for this session looks like.

Sensor Name: hacom
Timestamp: 2007-11-23 21:32:47
Connection ID: .hacom_5136151961070210685
Src IP: 69.255.105.234 (c-69-255-105-234.hsd1.va.comcast.net)
Dst IP: 164.106.251.250 (Unknown)
Src Port: 58172
Dst Port: 80
OS Fingerprint: 69.255.105.234:58172 - UNKNOWN
[S4:61:1:60:M1460,S,T,N,W4:.:?:?] (up: 3 hrs)
OS Fingerprint: -> 164.106.251.250:80 (link: ethernet/modem)

SRC: GET /docs/netsec/robert-morris.avi HTTP/1.0
SRC: User-Agent: Wget/1.10.2
SRC: Accept: */*
SRC: Host: 164.106.251.250
SRC: Connection: Keep-Alive
SRC:
SRC:
DST: HTTP/1.1 200 OK
DST: Date: Fri, 23 Nov 2007 21:38:16 GMT
DST: Server: Apache/2.0.52 (Red Hat)
DST: Last-Modified: Tue, 23 Aug 2005 21:46:31 GMT
DST: ETag: "37804f-6bfad96-ba9f7bc0"
DST: Accept-Ranges: bytes
DST: Content-Length: 113225110
DST: Connection: close
DST: Content-Type: video/x-msvideo
DST:
DST:
DST: RIFF....AVI LISTF...hdrlavih8...5...D.&......................I..
LISTt...strlstrh8...vidsmjpg............5...@B...........I...'..............
strf(...(...............MJPG....................LIST\...strlstrh8...auds....
.................+......\
DST: ..+...'..............strf.........+...+......IDIT....
FRI JUL 29 15:54:43 2005
DST: .LIST....INFOISFT....CanonMVI02..JUNK~...

After the HTTP response you see the download begin for the .avi. Presumably this would match, this rule?

"HTTP Download > 100M - Audio Video Interleave (AVI) File - RIFF"

Let's look at the two most important packets in the full content pcap file.

16:32:47.335530 IP 164.106.251.250.80 > 69.255.105.234.58172:
P 1:268(267) ack 133 win 1716 <nop,nop,timestamp 2163691250 1274738>
0x0000: 4520 013f e980 4000 3006 0fca a46a fbfa E..?..@.0....j..
0x0010: 45ff 69ea 0050 e33c f12d d653 a3ca 374e E.i..P.<.-.S..7N
0x0020: 8018 06b4 ce3b 0000 0101 080a 80f7 4ef2 .....;........N.
0x0030: 0013 7372 4854 5450 2f31 2e31 2032 3030 ..srHTTP/1.1.200
0x0040: 204f 4b0d 0a44 6174 653a 2046 7269 2c20 .OK..Date:.Fri,.
0x0050: 3233 204e 6f76 2032 3030 3720 3231 3a33 23.Nov.2007.21:3
0x0060: 383a 3136 2047 4d54 0d0a 5365 7276 6572 8:16.GMT..Server
0x0070: 3a20 4170 6163 6865 2f32 2e30 2e35 3220 :.Apache/2.0.52.
0x0080: 2852 6564 2048 6174 290d 0a4c 6173 742d (Red.Hat)..Last-
0x0090: 4d6f 6469 6669 6564 3a20 5475 652c 2032 Modified:.Tue,.2
0x00a0: 3320 4175 6720 3230 3035 2032 313a 3436 3.Aug.2005.21:46
0x00b0: 3a33 3120 474d 540d 0a45 5461 673a 2022 :31.GMT..ETag:."
0x00c0: 3337 3830 3466 2d36 6266 6164 3936 2d62 37804f-6bfad96-b
0x00d0: 6139 6637 6263 3022 0d0a 4163 6365 7074 a9f7bc0"..Accept
0x00e0: 2d52 616e 6765 733a 2062 7974 6573 0d0a -Ranges:.bytes..
0x00f0: 436f 6e74 656e 742d 4c65 6e67 7468 3a20 Content-Length:.
0x0100: 3131 3332 3235 3131 300d 0a43 6f6e 6e65 113225110..Conne
0x0110: 6374 696f 6e3a 2063 6c6f 7365 0d0a 436f ction:.close..Co
0x0120: 6e74 656e 742d 5479 7065 3a20 7669 6465 ntent-Type:.vide
0x0130: 6f2f 782d 6d73 7669 6465 6f0d 0a0d 0a o/x-msvideo....
16:32:47.336654 IP 164.106.251.250.80 > 69.255.105.234.58172:
. 268:1636(1368) ack 133 win 1716 #60;nop,nop,timestamp 2163691250 1274738#62;
0x0000: 4520 058c e982 4000 3006 0b7b a46a fbfa E.....@.0..{.j..
0x0010: 45ff 69ea 0050 e33c f12d d75e a3ca 374e E.i..P.<.-.^..7N
0x0020: 8010 06b4 b5f8 0000 0101 080a 80f7 4ef2 ..............N.
0x0030: 0013 7372 5249 4646 8ead bf06 4156 4920 ..srRIFF....AVI.
0x0040: 4c49 5354 4601 0000 6864 726c 6176 6968 LISTF...hdrlavih
0x0050: 3800 0000 3582 0000 44d0 2600 0000 0000 8...5...D.&.....
0x0060: 1000 0100 0e07 0000 0000 0000 0200 0000 ................
0x0070: c649 0100 8002 0000 e001 0000 0000 0000 .I..............
0x0080: 0000 0000 0000 0000 0000 0000 4c49 5354 ............LIST
0x0090: 7400 0000 7374 726c 7374 7268 3800 0000 t...strlstrh8...
0x00a0: 7669 6473 6d6a 7067 0000 0000 0000 0000 vidsmjpg........
0x00b0: 0000 0000 3582 0000 4042 0f00 0000 0000 ....5...@B......
0x00c0: 0e07 0000 c649 0100 1027 0000 0000 0000 .....I...'......
0x00d0: 0000 0000 8002 e001 7374 7266 2800 0000 ........strf(...
0x00e0: 2800 0000 8002 0000 e001 0000 0100 1800 (...............
0x00f0: 4d4a 5047 0010 0e00 0000 0000 0000 0000 MJPG............
0x0100: 0000 0000 0000 0000 4c49 5354 5c00 0000 ........LIST\...
0x0110: 7374 726c 7374 7268 3800 0000 6175 6473 strlstrh8...auds
0x0120: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0130: 0100 0000 102b 0000 0000 0000 5c20 0a00 .....+......\...
0x0140: 102b 0000 1027 0000 0100 0000 0000 0000 .+...'..........
0x0150: 0000 0000 7374 7266 1000 0000 0100 0100 ....strf........
0x0160: 102b 0000 102b 0000 0100 0800 4944 4954 .+...+......IDIT
0x0170: 1a00 0000 4652 4920 4a55 4c20 3239 2031 ....FRI.JUL.29.1
0x0180: 353a 3534 3a34 3320 3230 3035 0a00 4c49 5:54:43.2005..LI
0x0190: 5354 1800 0000 494e 464f 4953 4654 0c00 ST....INFOISFT..
0x01a0: 0000 4361 6e6f 6e4d 5649 3032 0000 4a55 ..CanonMVI02..JU
0x01b0: 4e4b 7e06 0000 0000 0000 0000 0000 0000 NK~.............
...truncated...

Do you see it? The HTTP response code and the Content-Length statement appear in the first packet. The .avi begins in the second packet with RIFF. Snort doesn't fire an alert because all of the matches needed for the rule are not present in a single packet.

Technically, there's not much to worry about here -- at least not yet. I do worry about putting monitoring tools in the hands of people who don't know what they're doing and seeing them act on misconceptions. It's also important to identify the fact that this activity could violate wiretap and privacy laws.

Rabu, 21 November 2007

Tap vs Lightning Strike

Earlier this year my lab suffered a near lightning strike. A tree right outside the lab was struck by lightning, causing damage to multiple electronic and electrical devices outside and inside the building.

Outside, the lightning disabled an exterior lighting system and my phone lines. Inside, the lightning took a severe toll on the lab. The cable modem to the outside world was destroyed. The NIC on the lab firewall facing the cable modem was fried, along with a second NIC in the firewall. The NIC on a sensor watching a tap between the cable modem and firewall was also destroyed. So far, this is a grim story.

I have one good piece of news to report, and it involves the tap I mentioned sitting between the cable modem and firewall. The tap survived the lightning strike. More precisely, the tap continued to pass traffic even when its monitoring interface was damaged.

Had the tap been receiving traffic from the modem or firewall, it would have continued to pass it. This truly amazed me. Frequently monitoring practitioners worry that inserting a tap in their network architecture will introduce a single point of failure. In my experience, all of the components around the tap are more likely to fail. A well-engineered tap will continue to pass traffic -- perhaps even when struck by lightning!

The tap that survived my lab lightning strike was built by Net Optics. Congratulations to the Net Optics engineering and manufacturing teams for building quality hardware.

7 steps to better Solaris Network Settings

I was auditing one of our customer again and this time round, i managed to come up with a 7 step guide to better secure the TCP stack for Solaris. Well, you guys can add on for more.

1. Configure for more random TCP sequence number generation. Check that in(/etc/default/inetinit), the TCP_STRONG_ISS is set to 2. For instance, TCP_STRONG_ISS=2

2. IP forwarding is to be turned off to prevent the machine acting as a router. To disable IP forwarding, a file "/etc/notrouter" need to be present. If the file is missing, issue the following command to create one : touch /etc/notrouter

To prevent dynamic routes updates via the network, move "in.routed" and "in.rdisc" away from "/usr/sbin" directory by perform the following commands :
mv /usr/sbin/in.routed /export/home/cfgh/base
mv /usr/sbin/in.rdisc /export/home/cfgh/base

3. Change default kernel IP settings for better security. Following the following steps to change the kernel IP defaults values :

Setup files and environment:
touch /etc/init.d/exconfig
ln -s /etc/init.d/exconfig /etc/rc2.d/S70exconfig
chmod 744 /etc/init.d/exconfig /etc/rc2.d/S70exconfig

Edit file "/etc/init.d/exconfig" and add the following lines:
#!/bin/sh
# /etc/init.d/exconfig
RELEASE=`/usr/bin/uname -r`
release7 ()
{
/usr/sbin/ex -set /dev/ip ip_forwarding 0
/usr/sbin/ex -set /dev/ip ip_strict_dst_multihoming 1
/usr/sbin/ex -set /dev/ip ip_send_redirects 0
/usr/sbin/ex -set /dev/ip ip_ignore_redirect 1
/usr/sbin/ex -set /dev/ip ip_forward_src_routed 0
/usr/sbin/ex -set /dev/ip ip_forward_directed_broadcasts 0
/usr/sbin/ex -set /dev/ip ip_respond_to_echo_broadcast 0
/usr/sbin/ex -set /dev/tcp tcp_conn_req_max_q0 4096
/usr/sbin/ex -set /dev/tcp tcp_ip_abort_cinterval 60000
/usr/sbin/ex -set /dev/ip ip_respond_to_timestamp 0
/usr/sbin/ex -set /dev/ip ip_respond_to_timestamp_broadcast 0
/usr/sbin/ex -set /dev/ip ip_respond_to_address_mask_broadcast 0
/usr/sbin/ex -set /dev/arp arp_cleanup_interval 60000
id -a mqm > /dev/null 2>&1
if [ \$? -eq 0 ]
then
/usr/sbin/ex -set /dev/tcp tcp_keepalive_interval 600000
fi
}
release8 ()
{
/usr/sbin/ex -set /dev/ip ip6_forwarding 0
/usr/sbin/ex -set /dev/ip ip6_strict_dst_multihoming 1
/usr/sbin/ex -set /dev/ip ip6_send_redirects 0
/usr/sbin/ex -set /dev/ip ip6_ignore_redirect 1
/usr/sbin/ex -set /dev/ip ip6_forward_src_routed 0
/usr/sbin/ex -set /dev/ip ip_ire_arp_interval 60000
}
release6 ()
{
/usr/sbin/ex -set /dev/ip ip_respond_to_echo_broadcast 0
/usr/sbin/ex -set /dev/ip ip_forward_directed_broadcasts 0
/usr/sbin/ex -set /dev/ip ip_strict_dst_multihoming 1
/usr/sbin/ex -set /dev/ip ip_ignore_redirect 1
/usr/sbin/ex -set /dev/ip ip_forward_src_routed 0
}

if [ \$RELEASE = "5.7" ]
then
release7
elif [ \$RELEASE = "5.8" ] || [ \$RELEASE = "5.10" ] || [ \$RELEASE = "5.9" ]
then
release7
release8
elif [ \$RELEASE = "5.6" ]
then
release6
fi

4. Disable multicast from the server, edit the file "/etc/rc2.d/S72inetsvc" and comment out/remove the following lines :
#(
#if [ "$_INIT_NET_STRATEGY" = "dhcp" ]; then
# mcastif=`/sbin/dhcpinfo Yiaddr` || mcastif=$_INIT_UTS_NODENAME
#else
# mcastif=$_INIT_UTS_NODENAME
#fi
#
#echo "Setting default Ipv4 interface for multicase:" \
# "add net 224.0/4: gateway $mcastif
#
#/usr/sbin/route -n add -interface "224.0/4" "$mcastif" >/dev/null
#)&

For Solaris 10
Multicast would be disabled using /etc/rc2.d/S72inetsvc-os10

5. Denial of Service Prevention System Settings.
Services that must be disabled on all servers, unless required by business function from /etc/services. Services include: ftp-data ftp tftp pop2 pop3 pop-2 nntp chargen daytime discard echo finger talk who whois new-rwho klogin eklogin telnet systat netstat time

6. Prevent "core dump" generated by inetd as it may contain login information. This could be achieved by editing the file "/etc/rc2.d/S72inetsvc". Change the line :
/usr/sbin/inetd -s &
to /usr/bin/ulimit -c 0; /usr/sbin/inetd -s -t &
Note :
ulimit -c 0 : set the core file size to 0 byte
inetd -s -t : stand-alone server with tracing of all tcp connections

For Solaris 10
Create the script /etc/rc2.d/S72inetsvc-os10 as per below.
#cat /etc/rc2.d/S72inetsvc-os10
IPADDR=`netstat -nr | grep -w 224.0.0.0 | awk '{print $2}'`
/usr/sbin/route -n delete -interface "224.0/4" $IPADDR
/usr/sbin/svcadm enable inetd
/usr/sbin/inetadm -M tcp_trace=TRUE
#chmod 555 /etc/rc2.d/S72inetsvc-os10

7. .netrc files System Settings (.netrc files, .netrc files in root’s home directory). Files are not permitted, remove the files if any, issue command find / -name .netrc -print

The Hacka Man

Updating FreeBSD 7.0-BETA2 to 7.0-BETA3

Recently I posted FreeBSD Binary Upgrade News about developments with Colin Percival's FreeBSD Update tool. Today I performed a remote (via SSH) upgrade from FreeBSD 7.0-BETA2 to FreeBSD 7.0-BETA3 using FreeBSD Update. I document the process below so you can see how easy it is and for my future reference.

Here is uname output to show the OS version prior to upgrading.

# uname -a
FreeBSD myhost.mydomain.com 7.0-BETA2 FreeBSD 7.0-BETA2 #0:
Fri Nov 2 16:47:33 UTC 2007
root@logan.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC i386

I wasn't sure if the version of FreeBSD Update packaged with FreeBSD 7.0-BETA2 would natively support this process, so I gave it a try.

# freebsd-update -r 7.0-BETA3 upgrade
usage: freebsd-update [options] command ... [path]

Options:
-b basedir -- Operate on a system mounted at basedir
(default: /)
-d workdir -- Store working files in workdir
(default: /var/db/freebsd-update/)
-f conffile -- Read configuration options from conffile
(default: /etc/freebsd-update.conf)
-k KEY -- Trust an RSA key with SHA256 hash of KEY
-s server -- Server from which to fetch updates
(default: update.FreeBSD.org)
-t address -- Mail output of cron command, if any, to address
(default: root)
Commands:
fetch -- Fetch updates from server
cron -- Sleep rand(3600) seconds, fetch updates, and send an
email if updates were found
install -- Install downloaded updates
rollback -- Uninstall most recently installed updates

Ok, that didn't work. Time to retrieve the new version from Colin's site.

# fetch http://www.daemonology.net/freebsd-update/freebsd-update-upgrade.tgz
freebsd-update-upgrade.tgz 100% of 21 kB 104 kBps
# fetch http://www.daemonology.net/freebsd-update/freebsd-update-upgrade.tgz.asc
freebsd-update-upgrade.tgz.asc 100% of 187 B 640 kBps

I decided to follow Colin's advice to check the signature of the upgrade file. To do that I needed to install GnuPG.

# pkg_add -r gnupg
Fetching ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-7-current/Latest/gnupg.tbz... Done.
Fetching ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-7-current/All/openldap-client-2.3.39.tbz... Done.

************************************************************

The OpenLDAP client package has been successfully installed.

Edit
/usr/local/etc/openldap/ldap.conf
to change the system-wide client defaults.

Try `man ldap.conf' and visit the OpenLDAP FAQ-O-Matic at
http://www.OpenLDAP.org/faq/index.cgi?file=3
for more information.

************************************************************

Fetching ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-7-current/All/curl-7.16.3.tbz... Done.
Fetching ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-7-current/All/pth-2.0.7.tbz... Done.
Fetching ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-7-current/All/libiconv-1.11_1.tbz... Done.
Fetching ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-7-current/All/gettext-0.16.1_3.tbz... Done.
Fetching ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-7-current/All/libgpg-error-1.5.tbz... Done.
Fetching ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-7-current/All/libgcrypt-1.2.4_1.tbz... Done.
Fetching ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-7-current/All/libksba-1.0.1_1.tbz... Done.
Fetching ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-7-current/All/dirmngr-0.9.7_2.tbz... Done.

###############################################################################
A T T E N T I O N

In order to use gpg-agent, you need to install a pinentry dialog.

The following ports of pinentry dialogs are available:

security/pinentry-curses (ncurses based dialog)
security/pinentry-gtk (GTK 1.2 based dialog)
security/pinentry-gtk2 (GTK 2.x based dialog)
security/pinentry-qt (QT based dialog)

###############################################################################

Wow, that installed more dependencies than I expected. Here I import the PGP keys from FreeBSD,org.

# rehash
# fetch http://www.freebsd.org/doc/pgpkeyring.txt
pgpkeyring.txt 100% of 1406 kB 142 kBps 00m00s
# gpg --import pgpkeyring.txt
gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: key CA6CDFB2: public key "FreeBSD Security Officer " imported
gpg: key FF8AE305: public key "core-secretary@FreeBSD.org" imported
...edited...
gpg: key D069F2A0: duplicated user ID detected - merged
gpg: key D069F2A0: public key "Thomas Abthorpe " imported
gpg: Total number processed: 262
gpg: w/o user IDs: 1
gpg: imported: 261 (RSA: 36)
gpg: no ultimately trusted keys found

With the keys imported I verify the file I downloaded.

# gpg --verify freebsd-update-upgrade.tgz.asc freebsd-update-upgrade.tgz
gpg: Signature made Fri Nov 16 09:01:38 2007 EST using DSA key ID CA6CDFB2
gpg: Good signature from "FreeBSD Security Officer "
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: C374 0FC5 69A6 FBB1 4AED B131 15D6 8804 CA6C DFB2

Note I need to generate my own key and sign the FreeBSD Security Officer's key with my generated key if I want to avoid GPG's warnings, i.e.:

gpg --gen-key
gpg --sign-key security-officer@FreeBSD.org

Now I am ready to proceed with the upgrade.

# tar -xf freebsd-update-upgrade.tgz
# sh freebsd-update.sh -f freebsd-update.conf -r 7.0-BETA3 upgrade
Looking up update.FreeBSD.org mirrors... 1 mirrors found.
Fetching public key from update1.FreeBSD.org... done.
Fetching metadata signature for 7.0-BETA2 from update1.FreeBSD.org... done.
Fetching metadata index... done.
Fetching 2 metadata files... done.
Inspecting system... done.

The following components of FreeBSD seem to be installed:
kernel/generic src/base src/bin src/cddl src/contrib src/crypto src/etc
src/games src/gnu src/include src/krb5 src/lib src/libexec src/release
src/rescue src/sbin src/secure src/share src/sys src/tools src/ubin
src/usbin world/base world/dict world/doc world/games world/info
world/manpages world/proflibs

The following components of FreeBSD do not seem to be installed:
src/compat world/catpages

Does this look reasonable (y/n)? y

Fetching metadata signature for 7.0-BETA3 from update1.FreeBSD.org... done.
Fetching metadata index... done.
Fetching 1 metadata patches. done.
Applying metadata patches... done.
Fetching 1 metadata files...
Inspecting system... done.
Preparing to download files... done.
Fetching 1289 patches.....10....20....30....40....50....60....70....80....90....
...edited...
Applying patches... done.
Fetching 329 files... done.

The following files will be removed as part of updating to 7.0-BETA3-p0:
/etc/pf.conf
/usr/share/doc/es_ES.ISO8859-1/books/handbook/LEGALNOTICE.html
/usr/share/doc/fr_FR.ISO8859-1/books/handbook/x20872.html
/usr/share/doc/fr_FR.ISO8859-1/books/handbook/x20918.html
/usr/share/doc/fr_FR.ISO8859-1/books/handbook/x21123.html
/usr/share/examples/etc/pf.conf
/usr/src/etc/pf.conf

The following files will be added as part of updating to 7.0-BETA3-p0:
/boot/kernel/if_zyd.ko
/boot/kernel/if_zyd.ko.symbols
...edited...
/usr/share/examples/pf/pf.conf
/usr/src/share/examples/pf/pf.conf

The following files will be updated as part of updating to 7.0-BETA3-p0:
/bin/ps
/boot/kernel/3dfx.ko
...edited...
/usr/src/usr.sbin/wpa/wpa_supplicant/driver_freebsd.c
/var/named/etc/namedb/named.root

# sh freebsd-update.sh -f freebsd-update.conf install
Installing updates...
Kernel updates have been installed. Please reboot and run
"freebsd-update.sh install" again to finish installing updates.
# shutdown -r now

After a reboot I run the following.

# sh freebsd-update.sh -f freebsd-update.conf install
Installing updates... done.
# shutdown -r now

After a second reboot the system is completely upgraded.

$ uname -a
FreeBSD myhost.mydomain.com 7.0-BETA3 FreeBSD 7.0-BETA3 #0:
Fri Nov 16 22:20:33 UTC 2007
root@logan.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC i386

That's excellent. The whole process took only a few minutes.