1.5.7 Ensure kernel.yama.ptrace_scope is configured

Information

The ptrace() system call provides a means by which one process (the "tracer") may observe and control the execution of another process (the "tracee"), and examine and change the tracee's memory and registers.

The sysctl settings (writable only with CAP_SYS_PTRACE) are:

- 0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other process running under the same uid, as long as it is dumpable (i.e. did not transition uids, start privileged, or have called prctl(PR_SET_DUMPABLE...) already). Similarly, PTRACE_TRACEME is unchanged.
- 1 - restricted ptrace: a process must have a predefined relationship with the inferior it wants to call PTRACE_ATTACH on. By default, this relationship is that of only its descendants when the above classic criteria is also met. To change the relationship, an inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare an allowed debugger PID to call PTRACE_ATTACH on the inferior. Using PTRACE_TRACEME is unchanged.
- 2 - admin-only attach: only processes with CAP_SYS_PTRACE may use ptrace with PTRACE_ATTACH, or through children calling PTRACE_TRACEME.
- 3 - no attach: no processes may use ptrace with PTRACE_ATTACH nor via PTRACE_TRACEME. Once set, this sysctl value cannot be changed.

If one application is compromised, it would be possible for an attacker to attach to other running processes (e.g. Bash, Firefox, SSH sessions, GPG agent, etc) to extract additional credentials and continue to expand the scope of their attack.

Enabling restricted mode will limit the ability of a compromised process to PTRACE_ATTACH on other processes running under the same user. With restricted mode, ptrace will continue to work with root user.

Solution

- Review all files being used by systemd sysctl and comment out or remove all kernel.yama.ptrace_scope lines that are not kernel.yama.ptrace_scope=1 kernel.yama.ptrace_scope=2 or kernel.yama.ptrace_scope=3

Example script:

#!/usr/bin/env bash

{
l_option="kernel.yama.ptrace_scope" l_value="(1|2|3)"
l_grep="${l_option//./(\\.|\\/)}" a_files=()
l_systemdsysctl="$(readlink -e /lib/systemd/systemd-sysctl \
|| readlink -e /usr/lib/systemd/systemd-sysctl)"
l_ufw_file="$([ -f /etc/default/ufw ] && \
awk -F= '/^\s*IPT_SYSCTL=/ {print $2}' /etc/default/ufw)"
[ -f "$(readlink -e "$l_ufw_file")" ] && \
a_files+=("$l_ufw_file"); a_files+=("/etc/sysctl.conf")
while IFS= read -r l_fname; do
l_file="$(readlink -e "${l_fname//# /}")"
[ -n "$l_file" ] && ! grep -Psiq -- '(^|\h+)'"$l_file"'\b' \
<<< "${a_files[*]}" && a_files+=("$l_file")
done < <("$l_systemdsysctl" --cat-config | tac | \
grep -Pio '^\h*#\h*\/[^#\n\r\h]+\.conf\b')
for l_file in "${a_files[@]}"; do
grep -Poi '\h*'"$l_grep"'\h*=\h*\H+\b' "$l_file" \
| grep -Pivq '^\h*'"$l_grep"'\h*=\h*'"$l_value"'\b' && \
sed -ri '/^\s*'"$l_grep"'\s*=\s*(0|4-9|1[0-9]+)/s/^/# /' "$l_file"
done
} <xhtml:ol start="2"> - Create or edit a file in the /etc/sysctl.d/ directory ending inconf and edit or add the following line:

kernel.yama.ptrace_scope = {N}

Example:

# [ ! -d "/etc/sysctl.d/" ] && mkdir -p /etc/sysctl.d/
# printf '%s\n' "" "kernel.yama.ptrace_scope = 1" >> /etc/sysctl.d/60-kernel_sysctl.conf

Note: The example uses kernel.yama.ptrace_scope = 1 but value may be set to 1 2 or 3

<xhtml:ol start="3"> - Run the following command to load all system configuration filles:

# sysctl --system

See Also

https://workbench.cisecurity.org/benchmarks/23597