Bug #15702
Updated by Jim Pingle 3 months ago
When there are multiple DHCP client interfaces on an installation, DHCP ACK packets from DHCP servers on some interfaces may be routed unexpectedly in certain situations, leading to a potential information disclosure. Notably, this happens when an interface address is renewed, such as by clicking the button on *Status > Interfaces*. The DHCP ACK packet sent by the WAN2 DHCP server is processed by @dhclient@ but at the time that ACK packet arrives, the destination address is not yet configured on an interface. Since the destination address is not on an interface, the OS does not know the packet is local, so it routes the packet according to the route table. In most cases this means the DHCP ACK from WAN2 will egress toward the WAN1 gateway. The ACK still has the source address of the WAN2 DHCP server and destination of what should be the new WAN2 address. Since the DHCP ACK packet from WAN2 contains address information from WAN2, but is sent out WAN1, the gateway on WAN1 receives information about addresses on WAN2, thus it is a potential information disclosure. The easiest way to reproduce this is to configure two DHCP client WANs on different segments, packet capture on both segments (upstream or locally), and then release/renew on WAN2. The DHCP request goes out WAN2, then the ACK comes back in WAN2 and then exits out WAN1. A potential workaround that appears to suppress the behavior is to remove state tracking from add @route-to ( lo0 127.0.0.1 )@ on the inbound DHCP rules and also tag inbound packets so they can be prevented from egressing other WANs: rules: <pre><code class="diff"> diff --git a/src/etc/inc/filter.inc b/src/etc/inc/filter.inc index 398b01ca87..f723eaa3ca 743633d93a..3ce81aa8ef 100644 --- a/src/etc/inc/filter.inc +++ b/src/etc/inc/filter.inc @@ -3935,6 +3935,7 -3948,7 +3948,7 @@ EOD; * Useful for protecting against sudden outbursts, etc. */ $ipfrules .= "block in {$log['block']} quick from <virusprot> to any ridentifier 1000000400 label \"virusprot overload table\"\n"; + $ipfrules .= "block out quick proto udp from any port = 67 to any port = 68 tagged \"dhcpin\" ridentifier {$increment_tracker()} label \"Prevent routing dhcp responses\"\n"; foreach ($FilterIflist as $on => $oc) { $saved_tracker += 10; @@ -3948,8 +3949,8 @@ EOD; } $ipfrules .= <<<EOD # allow our DHCP client out to the {$oc['descr']} -pass in {$log['pass']} quick on \${$oc['descr']} proto udp from any port = 67 to any port = 68 ridentifier {$increment_tracker()} label "{$fix_rule_label("allow dhcp replies in {$oc['descr']}")}" -pass out {$log['pass']} quick on \${$oc['descr']} proto udp from any port = 68 to any port = 67 ridentifier {$increment_tracker()} label "{$fix_rule_label("allow dhcp client out {$oc['descr']}")}" {$vlantag} +pass in {$log['pass']} quick on \${$oc['descr']} route-to ( lo0 127.0.0.1 ) proto udp from any port = 67 to any port = 68 tag "dhcpin" no state ridentifier {$increment_tracker()} label "{$fix_rule_label("allow dhcp replies in {$oc['descr']}")}" +pass pass out {$log['pass']} quick on \${$oc['descr']} proto udp from any port = 68 to any port = 67 no state ridentifier {$increment_tracker()} label "{$fix_rule_label("allow dhcp client out {$oc['descr']}")}" {$vlantag} # Not installing DHCP server firewall rules for {$oc['descr']} which is configured for DHCP. EOD; </code></pre> It's not clear if that is the best solution, however, and it needs more testing to ensure it doesn't lead to any other issues.