Hardening

From Segfault
Jump to: navigation, search

Operating Systems

Programs

GCC

A good set of options[1][2] to GCC seems to be:

CFLAGS="-Wall -Wextra -Wconversion -Wsign-conversion -Wformat-security -Werror=format-security \
        -fstack-protector-strong -Wstack-protector --param ssp-buffer-size=4 -pie -fPIE -ftrapv \
        -D_FORTIFY_SOURCE=2 -O2 -Wl,-z,relro,-z,now"

Some options explained:

-Wall                    Enables all the warnings about constructions that some users consider questionable
-Wextra                  Enables some extra warning flags that are not enabled by -Wall
-Wconversion             Warn for implicit conversions that may alter a value
-Wsign-conversion        Warn for implicit conversions that may change the sign of an integer value (enabled by -Wconversion in C)
-Wformat=2               Check format types and conversations, plus additional format checks
-Wformat-security        Also warn about uses of format functions that represent possible security problems
-Werror=format-security  Turn -Wformat warnings into errors
-fstack-protector-strong Emit extra code to check for buffer overflows, such as stack smashing attacks
-Wstack-protector        Warn about functions that are not protected against stack smashing
 ssp-buffer-size=4       Minimum size of buffers that receive stack smashing protection
-pie                     Produce a position independent executable on targets that support it (randomization)
-fPIE                    Needed by -pie
-ftrapv                  Generates traps for signed overflow on addition, subtraction, multiplication operations
-D_FORTIFY_SOURCE=2 -O2  Compile-time protection against static sized buffer overflows, -O2 is needed (?)
-Wl,-z,relro,-z,now      Mark various ELF memory sections read­only before handing over the program execution[3]

In Debian, hardening-wrapper and hardening-includes can be installed. GCC will then be wrapped and the hardening options will be set automatically if DEB_BUILD_HARDENING=1 is set:

$ ls -go `which gcc gcc-4.9` 
lrwxrwxrwx. 1  7 Feb 25 13:13 /usr/bin/gcc -> gcc-4.9
lrwxrwxrwx  1 11 Sep 24  2014 /usr/bin/gcc-4.9 -> hardened-cc

Some binaries were already compiled with some hardening options:

$ hardening-check /usr/sbin/sshd
/usr/sbin/sshd:
 Position Independent Executable: yes
 Stack protected: yes
 Fortify Source functions: yes (some protected functions found)
 Read-only relocations: yes
 Immediate binding: yes

This has been superseeded by setting default flags to the Debian build framework:

$ dpkg-buildflags --export=sh
export CFLAGS="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security"
export LDFLAGS="-Wl,-z,relro"
[...]

Populate the environment with (some[4] of) these flags:

export CFLAGS="-Wformat -Werror=format-security -fstack-protector-strong -pie -fPIE -D_FORTIFY_SOURCE=2 --param ssp-buffer-size=4" LDFLAGS="-Wl,-z,relro,-z,now"

export CXXFLAGS=$CFLAGS OBJCFLAGS=$CFLAGS OBJCXXFLAGS=$CFLAGS
export CPPFLAGS="-D_FORTIFY_SOURCE=2"

SSH

Enforce SSH protocol 2 only, permit root-login with keys only, disallow empty passwords, disable password-authenticaton, enable PAM:

$ cat /etc/ssh/sshd_config
[...]
Protocol               2
PermitRootLogin        without-password
PubkeyAuthentication   yes
PermitEmptyPasswords   no
PasswordAuthentication no
UsePAM                 yes

Be sure to adjust the TCP wrapper for SSH access. Also, with PAM we can set per-host and/or per-user restrictions:

$ grep pam_access /etc/pam.d/sshd 
account  required     pam_access.so
$ grep -v \# /etc/security/access.conf 
+  : root   : 127.0.0.1 10.2.0.0/24 12.34.56.78
-  : root   : ALL
+  : bob    : ALL
+  : alice  : 192.168.0.0/24 .example.com
-  : ALL    : ALL

Also, with public-key authentication, we can restrict connections on a per-key basis:

$ cat ~bob/.ssh/authorized_keys
from="*.example.com",command="/usr/local/sbin/validate-rsync.sh" [...]
$ cat ~alice/.ssh/authorized_keys
from="tunnel.example.com",no-agent-forwarding,no-pty,no-user-rc,no-X11-forwarding,permitopen="localhost:1234" [...]

tcpd

Many network daemons are linked against libwrap, implementing TCP wrapper functionality:

$ ldd `which mysqld` `which sshd`
[...]
/usr/sbin/mysqld:
       libwrap.so.0 => /lib/libwrap.so.0 (0x00007f7ebded8000)
/usr/sbin/sshd:
       libwrap.so.0 => /lib/libwrap.so.0 (0x00007fe29bd05000)

With this in place, we can restrict access to these services:

$ cat /etc/hosts.allow
sshd    : /etc/hosts.allow.networks
mysqld  : 12.34.56.78
ALL     : 127.0.0.1
ALL     : 10.30.0.0/255.255.255.0

$ cat /etc/hosts.allow.networks
backup.example.com
10.40.0.1
10.40.0.2

$ cat /etc/hosts.deny
ALL: PARANOID
ALL: ALL

Note that this is restricting access on a TCP level and does not replace an IP level firewall!

We can also restrict access to the hosts.allow* files:

chmod 0640 /etc/hosts.allow*
setfacl -m u:daemon:r /etc/hosts.allow*           # Allow portmap resp. rpcbind
setfacl -m u:bob:r /etc/hosts.allow*              # Allow user bob

See also

Links

References