Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces

Classification:

compliance

Framework:

Control:

Description

To set the runtime status of the net.ipv4.tcp_syncookies kernel parameter, run the following command:

$ sudo sysctl -w net.ipv4.tcp_syncookies=1

To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:

net.ipv4.tcp_syncookies = 1

Rationale

A TCP SYN flood attack can cause a denial of service by filling a system’s TCP connection table with connections in the SYN_RCVD state. Syncookies can be used to track a connection when a subsequent ACK is received, verifying the initiator is attempting a valid connection and is not a flood source. This feature is activated when a flood condition is detected, and enables the system to continue servicing valid connection requests.

Remediation

Shell script

The following script can be run on the host to remediate the issue.

# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv4.tcp\_syncookies from /etc/sysctl.d/\*.conf files

for f in /etc/sysctl.d/\*.conf /run/sysctl.d/\*.conf /usr/local/lib/sysctl.d/\*.conf /usr/lib/sysctl.d/\*.conf; do

 matching\_list=$(grep -P '^(?!#).\*[\s]\*net.ipv4.tcp\_syncookies.\*$' $f | uniq )
 if ! test -z "$matching\_list"; then
 while IFS= read -r entry; do
 escaped\_entry=$(sed -e 's|/|\\/|g' <<< "$entry")
 # comment out "net.ipv4.tcp\_syncookies" matches to preserve user data
 sed -i "s/^${escaped\_entry}$/# &/g" $f
 done <<< "$matching\_list"
 fi
done

#
# Set sysctl config file which to save the desired value
#

SYSCONFIG\_FILE="/etc/sysctl.conf"

sysctl\_net\_ipv4\_tcp\_syncookies\_value=''


#
# Set runtime for net.ipv4.tcp\_syncookies
#
/sbin/sysctl -q -n -w net.ipv4.tcp\_syncookies="$sysctl\_net\_ipv4\_tcp\_syncookies\_value"

#
# If net.ipv4.tcp\_syncookies present in /etc/sysctl.conf, change value to appropriate value
# else, add "net.ipv4.tcp\_syncookies = value" to /etc/sysctl.conf
#

# Strip any search characters in the key arg so that the key can be replaced without
# adding any search characters to the config file.
stripped\_key=$(sed 's/[\^=\$,;+]\*//g' <<< "^net.ipv4.tcp\_syncookies")

# shellcheck disable=SC2059
printf -v formatted\_output "%s = %s" "$stripped\_key" "$sysctl\_net\_ipv4\_tcp\_syncookies\_value"

# If the key exists, change it. Otherwise, add it to the config\_file.
# We search for the key string followed by a word boundary (matched by \>),
# so if we search for 'setting', 'setting2' won't match.
if LC\_ALL=C grep -q -m 1 -i -e "^net.ipv4.tcp\_syncookies\\>" "${SYSCONFIG\_FILE}"; then
 escaped\_formatted\_output=$(sed -e 's|/|\\/|g' <<< "$formatted\_output")
 LC\_ALL=C sed -i --follow-symlinks "s/^net.ipv4.tcp\_syncookies\\>.\*/$escaped\_formatted\_output/gi" "${SYSCONFIG\_FILE}"
else
 if [[ -s "${SYSCONFIG\_FILE}" ]] && [[ -n "$(tail -c 1 -- "${SYSCONFIG\_FILE}" || true)" ]]; then
 LC\_ALL=C sed -i --follow-symlinks '$a'\\ "${SYSCONFIG\_FILE}"
 fi
 printf '%s\n' "$formatted\_output" >> "${SYSCONFIG\_FILE}"
fi

else
 >&2 echo 'Remediation is not applicable, nothing was done'
fi

Ansible playbook

The following playbook can be run with Ansible to remediate the issue.

- name: List /etc/sysctl.d/\*.conf files
 find:
 paths:
 - /etc/sysctl.d/
 - /run/sysctl.d/
 - /usr/local/lib/sysctl.d/
 - /usr/lib/sysctl.d/
 contains: ^[\s]\*net.ipv4.tcp\_syncookies.\*$
 patterns: '\*.conf'
 file\_type: any
 register: find\_sysctl\_d
 when: ansible\_virtualization\_type not in ["docker", "lxc", "openvz", "podman", "container"]
 tags:
 - CJIS-5.10.1.1
 - DISA-STIG-UBTU-20-010412
 - NIST-800-171-3.1.20
 - NIST-800-53-CM-6(a)
 - NIST-800-53-CM-7(a)
 - NIST-800-53-CM-7(b)
 - NIST-800-53-SC-5(1)
 - NIST-800-53-SC-5(2)
 - NIST-800-53-SC-5(3)(a)
 - PCI-DSS-Req-1.4.1
 - disable\_strategy
 - low\_complexity
 - medium\_disruption
 - medium\_severity
 - reboot\_required
 - sysctl\_net\_ipv4\_tcp\_syncookies

- name: Comment out any occurrences of net.ipv4.tcp\_syncookies from config files
 replace:
 path: '{{ item.path }}'
 regexp: ^[\s]\*net.ipv4.tcp\_syncookies
 replace: '#net.ipv4.tcp\_syncookies'
 loop: '{{ find\_sysctl\_d.files }}'
 when: ansible\_virtualization\_type not in ["docker", "lxc", "openvz", "podman", "container"]
 tags:
 - CJIS-5.10.1.1
 - DISA-STIG-UBTU-20-010412
 - NIST-800-171-3.1.20
 - NIST-800-53-CM-6(a)
 - NIST-800-53-CM-7(a)
 - NIST-800-53-CM-7(b)
 - NIST-800-53-SC-5(1)
 - NIST-800-53-SC-5(2)
 - NIST-800-53-SC-5(3)(a)
 - PCI-DSS-Req-1.4.1
 - disable\_strategy
 - low\_complexity
 - medium\_disruption
 - medium\_severity
 - reboot\_required
 - sysctl\_net\_ipv4\_tcp\_syncookies
- name: XCCDF Value sysctl\_net\_ipv4\_tcp\_syncookies\_value # promote to variable
 set\_fact:
 sysctl\_net\_ipv4\_tcp\_syncookies\_value: !!str 
 tags:
 - always

- name: Ensure sysctl net.ipv4.tcp\_syncookies is set
 sysctl:
 name: net.ipv4.tcp\_syncookies
 value: '{{ sysctl\_net\_ipv4\_tcp\_syncookies\_value }}'
 sysctl\_file: /etc/sysctl.conf
 state: present
 reload: true
 when: ansible\_virtualization\_type not in ["docker", "lxc", "openvz", "podman", "container"]
 tags:
 - CJIS-5.10.1.1
 - DISA-STIG-UBTU-20-010412
 - NIST-800-171-3.1.20
 - NIST-800-53-CM-6(a)
 - NIST-800-53-CM-7(a)
 - NIST-800-53-CM-7(b)
 - NIST-800-53-SC-5(1)
 - NIST-800-53-SC-5(2)
 - NIST-800-53-SC-5(3)(a)
 - PCI-DSS-Req-1.4.1
 - disable\_strategy
 - low\_complexity
 - medium\_disruption
 - medium\_severity
 - reboot\_required
 - sysctl\_net\_ipv4\_tcp\_syncookies