Talk:Security Handbook/Firewalls and Network Security

From Gentoo Wiki
Jump to:navigation Jump to:search
Note
This is a Talk page - please see the documentation about using talk pages. Add newer comments below older ones, sign comments using four tildes (~~~~), and indent successive comments with colons (:). Add new sections at the bottom of the page, under a heading (== ==). Please remember to mark sections as "open for discussion" using {{talk|open}}, so they will show up in the list of open discussions.

A single firewall or firewall type is generally insufficient to secure an entire network

Talk status
This discussion is still ongoing.

I am not happy with this statement ... because it is wrong. In nearly every small company, with a small network this solution is active:

https://en.wikipedia.org/wiki/DMZ_(computing)#Single_firewall

I have even created an example configuration for this design:

https://forums.gentoo.org/viewtopic-t-1114432.html

Yes, it is a SPOF but with a correct configuration it is a very secure solution. Think how many samll companies have the money for an edge and a core firewall ?

pietinger 07:40, 31 August 2023 (UTC)

Sentence removed, and I improved some of the other phrasing around it.
JM01085758 (talk) 00:27, 6 September 2023 (UTC)

Firewall script audit

Talk status
This discussion is still ongoing.

In 2015, M. Marchese published a firewall script that creates the chain check-flags. The context says, Port scans should be detected and logged, but in reality the chain will never be executed. The problem is that the chain is attached after this rule:

$IPTABLES -A INPUT -m state --state INVALID -j DROP

which is equivalent [1] to:

$IPTABLES -A INPUT -m conntrack --ctstate INVALID -j DROP

Here is the code that demonstrates what decision conntrack will make based on the flags provided in the firewall script:

CODE demo.c (conntrack vs M. Marchese)
#include <stdio.h>
#include <stdint.h>

/**
 * The code block is taken from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/net/tcp.h
 * @license GPL-2.0-or-later
 */
#define TCPHDR_FIN 0x01
#define TCPHDR_SYN 0x02
#define TCPHDR_RST 0x04
#define TCPHDR_PSH 0x08
#define TCPHDR_ACK 0x10
#define TCPHDR_URG 0x20

/**
 * The code block is taken from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/netfilter/nf_conntrack_proto_tcp.c
 * @license GPL-2.0-only
 */
static const uint8_t tcp_valid_flags[(TCPHDR_FIN | TCPHDR_SYN | TCPHDR_RST | TCPHDR_ACK | TCPHDR_URG) + 1] =
{
  [TCPHDR_SYN]                          = 1,
  [TCPHDR_SYN|TCPHDR_URG]               = 1,
  [TCPHDR_SYN|TCPHDR_ACK]               = 1,
  [TCPHDR_RST]                          = 1,
  [TCPHDR_RST|TCPHDR_ACK]               = 1,
  [TCPHDR_FIN|TCPHDR_ACK]               = 1,
  [TCPHDR_FIN|TCPHDR_ACK|TCPHDR_URG]    = 1,
  [TCPHDR_ACK]                          = 1,
  [TCPHDR_ACK|TCPHDR_URG]               = 1,
};

void print(const char* string, uint8_t flags) {
  const uint8_t result = tcp_valid_flags[flags];
  printf("%s: %d: %d \n", string, flags, result);
}

/**
 *                   01
 *          01                01
 *      01       01       01      01
 *   01   01  01   01  01   01  01  01
 */
void combine(const char* string, const uint8_t any[], uint8_t result, int index) {
  if (index < 4) {
    const uint8_t new_result = result | any[index];
    print(string, new_result);
    combine(string, any, new_result, index + 1);
    combine(string, any, result, index + 1);
  }
}

void main() {
  // "ALL <BLAH>" means everyhing is zero except <BLAH> (see iptables man page (--tcp-flags))
  print("ALL FIN,URG,PSH", TCPHDR_FIN | TCPHDR_URG | TCPHDR_PSH);
  print("ALL ALL", TCPHDR_FIN | TCPHDR_SYN | TCPHDR_RST | TCPHDR_PSH | TCPHDR_ACK | TCPHDR_URG); // ACCEPTED (63)
  print("ALL SYN,RST,ACK,FIN,URG", TCPHDR_SYN | TCPHDR_RST | TCPHDR_ACK | TCPHDR_FIN | TCPHDR_URG);
  print("ALL NONE", 0);

  // SYN,RST SYN,RST (63 and 62 are ACCEPTED)
  const uint8_t any[] = { TCPHDR_FIN, TCPHDR_PSH, TCPHDR_ACK, TCPHDR_URG };
  combine("SYN,RST SYN,RST", any, TCPHDR_SYN | TCPHDR_RST, 0);

  // SYN,FIN SYN,FIN (63 and 59 are ACCEPTED)
  const uint8_t any2[] = { TCPHDR_RST, TCPHDR_PSH, TCPHDR_ACK, TCPHDR_URG };
  combine("SYN,FIN SYN,FIN", any2, TCPHDR_SYN | TCPHDR_FIN, 0);
}

The above code demonstrates that tcp_valid_flags filters all provided flags except 59, 62, 63. But conntrack has additional checks, so these packages are also dropped.

Here is a demonstration of the drop:

Firewall:

root #iptables --append INPUT --in-interface lo --protocol tcp --dport www --match conntrack --ctstate INVALID --jump DROP
root #iptables --append INPUT --in-interface lo --protocol tcp --dport www --jump ACCEPT

Scan:

root #nmap --scanflags 63 -p 80 localhost

Result:

root #iptables --list INPUT --verbose
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    2    88 DROP       tcp  --  lo     any     anywhere             anywhere             tcp dpt:http ctstate INVALID
    0     0 ACCEPT     tcp  --  lo     any     anywhere             anywhere             tcp dpt:http

pkts shows that packets were dropped.

--Lars Hint (talk) 10:19, 13 March 2024 (UTC)