Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Building Firewalls With OpenBSD And PF, 2nd Edition (2003)

.pdf
Скачиваний:
39
Добавлен:
17.08.2013
Размер:
2.74 Mб
Скачать

Section 8.1: The Anatomy of a Filtering Rule

167

 

 

# block packets destined for port 80

block in on $ext_if proto tcp from any to \ $dmz_www_ad port = 80

# block packets destined for all ports except port 80 block in on $ext_if proto tcp from any to \

$dmz_www_ad port != 80

# block packets destined for ports lower than port 80 block in on $ext_if proto tcp from any to \

$dmz_www_ad port < 80

#block packets destined for ports lower than and equal

#to port 80

block in on $ext_if proto tcp from any to \ $dmz_www_ad port <= 80

#block packets destined for ports higher than block in on $ext_if proto tcp from any \

to $dmz_www_ad port > 80

#block packets destined for ports higher than and equal

#to port 80

block in on $ext_if proto tcp from any to \ $dmz_www_ad port >= 80

#block packets destined for ports higher than port 80

#and lower than port 1024

block in on $ext_if proto tcp from any to \ $dmz_www_ad port 80 >< 1024

#block packets destined for ports lower than port 80

#and higher than port 1024

block in on $ext_if proto tcp from any to \ $dmz_www_ad port 80 <> 1024

Specifying port numbers makes sense only for those protocols that carry source port information (like TCP or UDP). That is why you need to use the proto keyword when you use the port keyword. Otherwise, pfctl(8) will complain and refuse to load rules.

168

Chapter 8: Packet Filtering

 

 

Port numbers and the names of services that use them are listed in /etc/services. The latest version of that list is available from:

http://www.iana.org/assignments/port-numbers

8.1.12 Sender's Operating System (os)

A new addition to pf(4) introduced in OpenBSD 3.4 is the ability to use the operating system Œngerprint database stored in /etc/pf.os. That database is a plain text Œle with one entry per line. You select Œngerprints using three Œelds: operating system name, operating system version, and subtype/patchlevel.

To use this feature add the os keyword followed by the Œngerprint parameters after the source port number speciŒcation, or (when port number information is missing, right after the source address). For example, if you wanted to match connections from Microsoft Windows, you would write:

pass in on $ext_if proto tcp from any os "Windows"

A more speciŒc rule, matching connections from Microsoft Windows 2000 hosts, would be:

pass in on $ext_if proto tcp from any os "Windows 2000"

And, if you wanted to be even more speciŒc, you could match packets from Microsoft Windows 2002 Service Pack 4 (SP4):

pass in on $ext_if proto tcp from any os "Windows 2000 SP4"

What if you wanted to be `creative' and used "Windows SP4?" It won't match. Check it for yourself, write such rule and load it with:

# pfctl -f ./test-os

And check what pfctl(8) reports. When it Œnds a matching entry in /etc/pf.os, you will see something like:

pass in on ne1 proto tcp from any os "Windows 2000 SP4"

Section 8.1: The Anatomy of a Filtering Rule

169

 

 

If there is no matching entry, you will see:

pass in on ne1 proto tcp from any os "nomatch"

Always check if the os rules resolve to the signatures you speciŒed, or you may be scratching your head wondering what is going on with them.

There are a few things you need to be aware of when you use this feature:

ƒoperating system Œngerprinting is not an exact science, and should not be though of as a security tool. It can be useful in Œne-tuning rules that regulate the •ow of packets (some hosts can connect to one host, while they cannot connect to another).

ƒit works for TCP connections only, so add the proto tcp keywords to such rules.

ƒthe match is done on the TCP SYN packet (sent at teh time when the remote host attempts to establish a new connection). Therefore, when you load os rules into memory, they will do nothing to existing connections.

ƒwhen you add a on rule to your ruleset, pf(4) automatically loads /etc/pf.os into memory. You can view its contents with:

# pfctl -so

ƒfor matching operating systems without entries in /etc/pf.os, use the unknown string, e.g:

pass in on ne1 proto tcp from any os "unknown"

Pf(4) expects to Œnd the Œngerprint database in /etc/pf.os, but you can change it with the following option:

set fingerprints "/etc/pf.os-special-modifications"

8.1.13 Destination IP address (to, any, all)

Destination address Œltering is typically used to pass only those packets that are destined to addresses where there are servers listening for connections, for example:

pass in on $ext_if from any to $dmz_www_ad

170

Chapter 8: Packet Filtering

 

 

All syntax rules for source addresses discussed earlier are applicable to destination addresses. Destination address speciŒcation is a required part of any packet Œltering rule, even if you use an all-encompassing any or all shortcuts.

8.1.14 Destination Port (port)

The destination port speciŒcation follows the destination address speciŒcation. All rules that apply to source ports, apply to destination ports. Of course, both are independent. You will probably use destination ports more often than source ports, as such rules are usually used to only let those packets through that are destined to ports where appropriate servers are listening, for example:

pass in on $ext_if proto tcp from any to \ $ext_www_ad port $ext_www_port

pass in on $ext_if proto tcp from any to \ $ext_smtp_ad port $ext_smtp_port

pass in on $ext_if proto tcp from any to \ $ext_ftp_ad port $ext_ftp_port

Ports (source or target) only make sense for TCP or UDP protocols, so if pfctl(8) complains about your rules, check if you narrowed your rules to TCP or UDP.

8.1.15 User and Group Access Control (user, group)

One very handy feature of pf(4) is its ability to Œlter packets based on the names of the users and groups who own the sockets on which packets are sent or received. The user and group IDs can be given in form of names or numbers and it is possible to specify ranges and lists of IDs. When you list ranges, it is possible to construct them using the operators described earlier in the section on source ports:

pass out on $ext_if proto {tcp, udp} \ from any to any user joe keep state

pass out on $ext_if proto {tcp, udp} \

from any to any user > 10000 group users keep state

Section 8.1: The Anatomy of a Filtering Rule

171

 

 

The user and group names are effective names, which may not be the same as the real name (as is the case with setuid and setgid processes). If you are having problems with these rules, remember that the user and group IDs are stored at the time a socket is created and they are not updated when the process creating a socket drops privileges (e.g., after a process binds to a privileged port as root, and then drops root privileges), so it may be that you need to use root ID in a rule instead of an unprivileged users's ID. Try this when you hit a stumbling block with rules user or group

In case of outgoing connections, the user IDs will match the user that opened the connection from the Œrewall itself. Similarly, for incoming connections, the user IDs will match the user that opened the socket for listening on the Œrewall. It is not possible to match usernames on connections forwarded with NAT rules. In case of forwarded connections, user or group IDs can match (or not match) a special username unknown. In this case, only two operators are allowed: = and !=.

User and group rules can only be used with TCP and

UDP protocols.

User and group names are used in ftp-proxy(8) setup described in Chapter 4, ConŒguring OpenBSD. Another application of user/group keywords is user authentication described in Chapter 12, Using authpf.

8.1.16 TCP Flags (•ags)

TCP packet headers contain a •ag Œeld which plays an important role in the process of establishing, maintaining, and closing connections. Flags are important from the point of view of security, because some attackers abuse the three-way-handshake mechanism and other uses of TCP •ags in denial of service (DOS) attacks (see CERT Advisories [CERT-1996.21] and [CERT-2000.21]) and other types of attacks aimed at hosts connected to the Internet.

As of OpenBSD 3.4, pf(4) recognizes the following TCP header •ags:

ƒ(S)YN: synchronize sequence numbers.

ƒ(A)CK: acknowledge.

ƒ(R)ST: reset.

172

Chapter 8: Packet Filtering

 

 

ƒ(F)IN: Œnish.

ƒ(P)USH: push.

ƒ(U)RG: urgent pointer.

ƒ(E)CE: (ECN-Echo) explicit congestion notiŒcation echo.

ƒC(W)R: congestion window reduced.

The syntax for this portion of Œltering rules is as follows: the flags keyword is followed by two lists of •ags separated with a slash (/); the Œrst is a list of •ags from the second list that must be set. Those •ags not on the Œrst list must be unset. Flags not listed on the second list are ignored, and those •ags from the second list missing from the Œrst list may or may not be set:

#FIN must be set, ignore the rest block in proto tcp all flags F/F

#FIN must be unset, ignore the rest block in all flags /F

#FIN must be set, the rest must be unset block in all flags F

#FIN must be set, ACK must be unset, ignore the rest block in all flags F/FA

#FIN and ACK must be unset, ignore the rest

block in all flags /FA

TCP •ags are described in [RFC 761] and [RFC 793]. A far more detailed discussion of TCP •ags can be found in [Wright, Stevens 1994] Note that [Wright, Stevens 1994] does not describe the ECE and CWR •ags, as these were added to the TCP header after it was published. For more information on ECE and CWR read [RFC 3168], [RFC 3168], and [RFC 3360].

The flags keyword makes sense only for TCP (proto tcp) packets.

8.1.17 ICMP Packets

Bogus ICMP packets are another way attackers can make your site inoperable, which is why pf(4) has special syntax for dealing with these useful, but potentially dangerous packets. For more information about the havoc ICMP packets can wreak read this paper:

http://www.giac.org/practical/gsec/DeokJo_Jeon_GSEC.pdf

Section 8.1: The Anatomy of a Filtering Rule

173

 

 

Additional information on that subject can be found in [CERT-1996.26].

ICMPv4 packets are matched by the icmp-type keyword, while ICMP IPv6 are matched by the ipv6-icmp-type keyword. Both keywords are followed by the ICMP type number and the ICMP code number, separated with the code keyword.

For example, if you wanted the Œrewall to receive and reply to ping requests, you'd use the following rule:

pass in inet proto icmp icmp-type 8 code 0 keep state

The equivalent rule for IPv6 would be:

pass in inet6 proto icmpv6 icmpv6-icmp-type 8 code 0 keep state

Explanations of ICMPv4 message types and codes can be found in [RFC 792], while ICMPv6 message types and codes are discussed in [RFC 2463].

8.1.18 Stateful Filtering (keep state, modulate state, synproxy state)

Pf(4) is a stateful packet Œlter, which means that it is capable of keeping track of the state of connections. Stateful Œltering has the following advantages:

ƒmakes packet processing faster

ƒmakes writing rulesets easier

ƒmakes connections safer

The basic principle behind stateful Œltering is simple. When the initial packet makes the connection on the Œrewall, the packet Œlter will create an entry in its state table for that connection. All subsequent packets that belong to the connection for which an entry in the state table exist will be let through without matching them against the whole ruleset. State tables are checked before the Œlter begins evaluating Œltering rules.

The packet Œlter decides if a packet belongs to a connection for which a state exists by checking the packet's sequence number stored in the TCP header. When the sequence number falls out of a narrow window, the packet is dropped. This mechanism prevents spoofed packet injection into

174

Chapter 8: Packet Filtering

 

 

an established connection. Stateful inspection of packets is turned on with the keep state keywords placed near the end of a Œltering rule (before queue lists, see Chapter 10, Bandwidth Shaping and Load Balancing):

pass out on $ext_if proto TCP all keep state

To keep memory usage under control, information about connections is removed from the state table after connections are closed or after they time out.

(By the way, when you use nat/binat/rdr rules, you are already using stateful Œltering, as these rules create states automatically.)

There are two schools of thought about state creation. Some administrators insist that only packets with the SYN •ag (i.e., the packets that initialize the connection) can create state. Others say that any packet ought to be able to create state, because such rules allow existing connections to create state and continue after the state tables are •ushed with pfctl -F state or after the Œrewall is rebooted. Rules that create state only for packets with the SYN •ag set will not be able to create state for existing connections.

The following rules allow all departing TCP packets to create state. As for inbound packets, only those sent to port 80 will be able to create state:

pass in proto tcp all port 80 keep state pass out proto tcp all keep state

If you want to limit packets that can create state to those that have the SYN •ag set, add the flags S/SA condition, as in:

pass in proto tcp all port 80 flags S/SA keep state pass out proto tcp all flags S/SA keep state

What about UDP or ICMP packets? Can pf(4) create state for these as well? Yes, it can. With UDP packets, which do not carry sequence numbers, the Œlter matches them to states using only address and port information.

As for ICMP, these are treated differently depending on their category. ICMP error messages that refer to TCP or UDP packets are matched against

Section 8.1: The Anatomy of a Filtering Rule

175

 

 

states for connections they refer to. As such they do not require separate rules, the packet Œlter will take care of this automatically. ICMP queries (like ping(8)) may need their own separate rules, like:

pass out inet proto icmp all icmp-type echoreq keep state

Initial sequence numbers, if chosen carelessly, can be used in dangerous attacks that exploit the fact that some TCP stacks use easily predictable values for initial sequence numbers. For more information about these attacks read [CERT VU#498440] or [Farrow 2003].

Pf(4) can prevent these attacks with the modulate state rule. To turn it on, use modulate state instead of keep state:

pass in proto tcp all port 80 flags S/SA keep state pass out proto tcp all flags S/SA keep state

becomes:

pass in proto tcp all port 80 flags S/SA modulate state pass out proto tcp all flags S/SA modulate state

The advantage of using modulate state is a higher level of security achieved by a more random initial sequence number chosen for connections that match such rules. Remember that modulate state can only be used with TCP connections. For other connections use keep state.

Another variant of stateful Œltering is SYNPROXY. The idea behind this kind of state rule is to complete the TCP connection initialization handshake on behalf of both sides and once that is completed, pass packets back and forth. The synproxy state rules implement both keep state and modulate state features and only work with TCP connections:

pass in proto tcp all port 80 flags S/SA synproxy state

SYNPROXY rules prevent SYN •oods, a particularly nasty type of attack.

The behavior of the state engine can be controlled with global options applicable to all rules, and with local options speciŒed on a per-rule basis. These options are: limit states and timeout.

176

Chapter 8: Packet Filtering

 

 

The limit states n option set hard limits on the number of memory pools used by pf(4) to store state table entries. If you set this option, pf(4) will store only n state table entries. Administrators use this option to avoid performance hits and to prevent attacks from overwhelming the Œrewall's resources. This option must be listed in the options section of /etc/pf.conf.

You can change these limits at will, but to reset them to their unlimited state, you have to comment out or remove set limit states rules in /etc/pf.conf, and reboot your Œrewall machine.

The timeout option rule adjusts the expiration time of stateful connections. These rules only apply to packets matching stateful connections. The general syntax of this rule is set timeout protocol.connectionstate timeout, for example:

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

#options: "set"

#ex. 1 sets timeout of the stateful connection to 20

#seconds after receiving the first packet from the host

#initializing this connection.

set timeout tcp.first 20

#ex. 2 sets timeout of the stateful connection to 20

#seconds after receiving the first packet from the host

#initializing this connection, then, if the connection

#is established, every packet that matches the

#established state of a TCP connection resets the

#timeout of the TCP connection it is a part of to 10

#seconds. This is very aggressive, and will result in

#a high percentage of lost valid connections on slow

#links.

set timeout tcp.first 20

set timeout tcp.established 10

#ex. 3 same as ex. 2, but both rules have been combined

#on a single line (the order of protocol.state rules is

#not relevant)

set timeout { tcp.first 20, tcp.established 10 }